*/}}
Browse Source

Restructured stuff and fixed ui destroy stop using call.

Yiming Wu 2 years ago
commit
3663dfbb77

+ 15 - 0
source/lagui/CMakeLists.txt

@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 3.1)
+#project (lagui)
+
+file(GLOB_RECURSE SOURCE_FILES 
+	./**.c
+	./**.cpp)
+	
+# Add header files
+file(GLOB_RECURSE HEADER_FILES 
+	./**.h
+	./**.hpp)
+
+add_definitions(-w)
+
+add_library(lagui ${HEADER_FILES} ${SOURCE_FILES})

+ 38 - 0
source/lagui/la_5.h

@@ -0,0 +1,38 @@
+#pragma once
+
+//NUL4.h resource management only
+
+#define _BSD_SOURCE  1
+#define _SVID_SOURCE 1
+
+#define BYTE uint8_t
+
+#ifdef __cplusplus
+    extern "C" {
+#endif
+
+#include "la_util.h"
+
+#include "la_interface.h"
+
+#include "la_data.h"
+//#include "la_icon.h"
+#include "la_tns.h"
+
+
+#ifdef __cplusplus
+    }
+#endif
+
+#include "math.h"
+//#include "LA_AV.h"
+//#include <direct.h>
+//#include <io.h>
+
+#include <unistd.h>
+#include <dirent.h>
+#include <locale.h>
+#include <stddef.h> //offsetof
+#include <stdio.h>
+#include <time.h>
+#include <sys/stat.h>

+ 309 - 0
source/lagui/la_controllers.c

@@ -0,0 +1,309 @@
+#include "la_5.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/input.h>
+#include <linux/joystick.h>
+
+extern LA MAIN;
+
+STRUCTURE(laJoystickEvent){
+  unsigned int time;
+  short value;
+  unsigned char type;
+  unsigned char number;
+};
+
+#define LA_JS_EVENT_BUTTON 0x01 // button pressed/released
+#define LA_JS_EVENT_AXIS   0x02 // joystick moved
+#define LA_JS_EVENT_INIT   0x80 // initial state of device
+
+#define LA_JS_TYPE_X56_THROTTLE 1
+#define LA_JS_TYPE_X56_STICK 2
+
+int la_IdentifyControllerInternalType(char* name){
+    if(strstr(name, "X-56") && strstr(name, "Throttle")){ return LA_JS_TYPE_X56_THROTTLE; }
+    if(strstr(name, "X-56") && strstr(name, "Stick")){ return LA_JS_TYPE_X56_STICK; }
+    return 0;
+}
+
+laController* la_NewController(char* name, char* path, int device, int NumAxes, int NumButtons){
+    laController* c=memAcquire(sizeof(laController));
+    logPrint("Found controller %s\n    at %s\n    with %d axes, %d buttons\n", name, path, NumAxes, NumButtons);
+    strSafeSet(&c->Name, name); strSafeSet(&c->Path, path); c->fd=device;
+    c->NumAxes = NumAxes; c->NumButtons=NumButtons;
+    c->InternalType = la_IdentifyControllerInternalType(name);
+    lstAppendItem(&MAIN.Controllers,c);
+    return c;
+}
+void la_DestroyController(laController* c){
+    free(c->ButtonValues); strSafeDestroy(&c->Name); strSafeDestroy(&c->Path);
+    memFree(c);
+}
+
+void la_InitControllers(){
+    char path[32]="/dev/input/js";
+    char name[128]={0};
+    int numpos=strlen(path);
+    for(int i=0;i<16;i++){
+        int fd;
+        int version; uint8_t axes, buttons;
+	    int btnmapok = 1;
+        sprintf(&path[numpos],"%d",i);
+        if ((fd=open(path, O_RDONLY|O_NONBLOCK))<0) { continue; }
+
+        ioctl(fd, JSIOCGVERSION, &version);
+        ioctl(fd, JSIOCGAXES, &axes);
+        ioctl(fd, JSIOCGBUTTONS, &buttons);
+        ioctl(fd, JSIOCGNAME(128), name);
+
+        laController* c=la_NewController(name, path, fd, axes, buttons);
+    }
+}
+
+void la_UpdateControllerStatus(){
+    laJoystickEvent event; int HasEvent=0;
+    for(laController* c=MAIN.Controllers.pFirst;c;c=c->Item.pNext){
+        while(read(c->fd, &event, sizeof(laJoystickEvent))>0){
+            if(event.type&LA_JS_EVENT_BUTTON){
+                if(event.number>=c->NumButtons) continue;
+                c->ButtonValues[event.number]=event.value; HasEvent=1;
+                printf("b %d %d\n", event.number, event.value);
+            }
+            if(event.type&LA_JS_EVENT_AXIS){
+                if(event.number>=c->NumAxes) continue;
+                c->AxisValues[event.number]=event.value;
+                printf("a %d %d\n", event.number, event.value); HasEvent=1;
+            }
+        }
+    }
+    if(HasEvent) laNotifyUsers("la.controllers");
+}
+
+void la_AddButtonProp(laPropContainer* pc, char* id, char* name, char* desc, int i, int array_len, char* array_prefix){
+    laProp* p=laAddEnumProperty(pc, id, name, desc, LA_WIDGET_ENUM_HIGHLIGHT,
+        array_prefix,0,0,0,offsetof(laController, ButtonValues[i]),0,0,array_len,0,0,0,0,0,0,LA_READ_ONLY);
+    laAddEnumItemAs(p,"IDLE", "Idle", "Button is not pressed", 0, 0);
+    laAddEnumItemAs(p,"ACTIVE", "Active", "Button is pressed", 1, 0);
+    p->ElementBytes=1;
+}
+void la_AddAxisProp(laPropContainer* pc, char* id, char* name, char* desc, int i, int array_len, char* array_prefix){
+    laProp* p=laAddIntProperty(pc,id,name,desc,array_len>1?LA_WIDGET_INT_METER_2D:LA_WIDGET_INT_METER,
+        array_prefix,0,32768,-32767,1,0,0,offsetof(laController, AxisValues[i]),0,0,array_len,0,0,0,0,0,0,0,LA_READ_ONLY);
+}
+void la_AddGenericButtonProps(laPropContainer* pc){
+    char id[16]=""; char name[16]=""; char Description[16]=""; laProp* p;
+    for(int i=0;i<LA_JS_MAX_BUTTONS;i++){
+        sprintf(id,"b%d",i); sprintf(name ,"%d",i); sprintf(Description ,"Button %d",i);
+        la_AddButtonProp(pc,id,name,Description,i,0,0);
+    }
+}
+void la_AddGenericAxisProps(laPropContainer* pc){
+    char id[4]=""; char name[4]=""; char Description[16]=""; laProp* p;
+    for(int i=0;i<LA_JS_MAX_AXES;i++){
+        sprintf(id,"a%d",i); sprintf(name ,"%d",i); sprintf(Description ,"Axis %d",i);
+        la_AddAxisProp(pc,id,name,Description,i,0,0);
+    }
+}
+
+void laui_X56Throttle(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context);
+void laui_X56Stick(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context);
+
+laPropContainer* LA_PC_JS_GENERIC;
+laPropContainer* LA_PC_JS_X56_THROTTLE;
+laPropContainer* LA_PC_JS_X56_STICK;
+
+laPropContainer* laget_ControllerType(laController* c){
+    switch(c->InternalType){
+    default: case 0: return LA_PC_JS_GENERIC;
+    case LA_JS_TYPE_X56_THROTTLE: return LA_PC_JS_X56_THROTTLE;
+    case LA_JS_TYPE_X56_STICK:    return LA_PC_JS_X56_STICK;
+    }
+}
+
+void la_RegisterControllerProps(){
+    laPropContainer* pc; laProp* p;
+
+    pc=laAddPropertyContainer("la_controller", "Controller", "A joystick/gamepad controller", L'🕹', 0, sizeof(laController), 0,0,1);
+    LA_PC_JS_GENERIC = pc;
+    laAddStringProperty(pc,"name","Name","Name of the controller", LA_WIDGET_STRING_PLAIN,0,0,0,1,offsetof(laController,Name),0,0,0,0,LA_READ_ONLY|LA_AS_IDENTIFIER);
+    laAddStringProperty(pc,"path","Path","Device path to the controller", LA_WIDGET_STRING_PLAIN,0,0,0,1,offsetof(laController,Path),0,0,0,0,LA_READ_ONLY);
+    la_AddGenericButtonProps(pc);
+    la_AddGenericAxisProps(pc);
+
+    pc=laAddPropertyContainer("la_controller_x56_throttle", "X56 Throttle", "X56 Throttle", 0,laui_X56Throttle,sizeof(laController),0,0,1);
+    LA_PC_JS_X56_THROTTLE = pc;
+    laAddStringProperty(pc,"name","Name","Name of the controller", LA_WIDGET_STRING_PLAIN,0,0,0,1,offsetof(laController,Name),0,0,0,0,LA_READ_ONLY|LA_AS_IDENTIFIER);
+    laAddSubGroup(pc,"base","Base","Generic controller status", "la_controller",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
+    la_AddAxisProp(pc,"thr1","THR1","Throttle 1",0,0,0);
+    la_AddAxisProp(pc,"thr2","THR2","Throttle 1",1,0,0);
+    la_AddAxisProp(pc,"wf","WF","Wheel F (big wheel)",2,0,0);
+    la_AddAxisProp(pc,"ball","Ball","Thumb ball",3,2,"Left/Right,Up/Down");
+    la_AddAxisProp(pc,"wg","WG","Wheel G (smaller wheel)",5,0,0);
+    la_AddAxisProp(pc,"r4","RTY4","Rotary 4",6,0,0);
+    la_AddAxisProp(pc,"r3","RTY3","Rotary 3",7,0,0);
+    la_AddButtonProp(pc,"be","E","Button E (thumb flat switch)", 0,0,0);
+    la_AddButtonProp(pc,"bf","F","Button F (big push down switch)", 1,0,0);
+    la_AddButtonProp(pc,"bg","G","Button G (smaller up-side-down switch)", 2,0,0);
+    la_AddButtonProp(pc,"bi","I","Button I (left reverser)", 3,0,0);
+    la_AddButtonProp(pc,"bh","H","Button H (right reverser)", 4,0,0);
+    la_AddButtonProp(pc,"sw1","SW1","Switch 1", 5,0,0);
+    la_AddButtonProp(pc,"sw2","SW2","Switch 2", 6,0,0);
+    la_AddButtonProp(pc,"sw3","SW3","Switch 3", 7,0,0);
+    la_AddButtonProp(pc,"sw4","SW4","Switch 4", 8,0,0);
+    la_AddButtonProp(pc,"sw5","SW5","Switch 5", 9,0,0);
+    la_AddButtonProp(pc,"sw6","SW6","Switch 6", 10,0,0);
+    la_AddButtonProp(pc,"t1_up","T1+","Toggle 1+", 11,0,0);
+    la_AddButtonProp(pc,"t1_dn","T1-","Toggle 1-", 12,0,0);
+    la_AddButtonProp(pc,"t2_up","T2+","Toggle 2+", 13,0,0);
+    la_AddButtonProp(pc,"t2_dn","T2-","Toggle 2-", 14,0,0);
+    la_AddButtonProp(pc,"t3_up","T3+","Toggle 3+", 15,0,0);
+    la_AddButtonProp(pc,"t3_dn","T3-","Toggle 3-", 16,0,0);
+    la_AddButtonProp(pc,"t4_up","T4+","Toggle 4+", 17,0,0);
+    la_AddButtonProp(pc,"t4_dn","T4-","Toggle 4-", 18,0,0);
+    la_AddButtonProp(pc,"h3","H3","Hat 3 (Upper round hat)", 19,4,"N,E,S,W");
+    la_AddButtonProp(pc,"h4","H4","Hat 4 (lower jagged hat)", 23,4,"N,E,S,W");
+    la_AddButtonProp(pc,"pinky_up","P+","Pinky up", 27,0,0);
+    la_AddButtonProp(pc,"pinky_dn","P-","Pinky down", 28,0,0);
+    la_AddButtonProp(pc,"dial_fwd","D+","Dial forward", 29,0,0);
+    la_AddButtonProp(pc,"dial_back","D-","Dial backward", 30,0,0);
+    la_AddButtonProp(pc,"bball","BP","Ball push", 31,0,0);
+    la_AddButtonProp(pc,"slider","SLD","Slider", 32,0,0);
+    la_AddButtonProp(pc,"mode","Mode","Mode switch", 33,3,"M1,M2,S1");
+
+
+    pc=laAddPropertyContainer("la_controller_x56_stick", "X56 Stick", "X56 Stick", 0,laui_X56Stick,sizeof(laController),0,0,1);
+    LA_PC_JS_X56_STICK = pc;
+    laAddStringProperty(pc,"name","Name","Name of the controller", LA_WIDGET_STRING_PLAIN,0,0,0,1,offsetof(laController,Name),0,0,0,0,LA_READ_ONLY|LA_AS_IDENTIFIER);
+    laAddSubGroup(pc,"base","Base","Generic controller status", "la_controller",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
+    la_AddAxisProp(pc,"stick","Stick","Main stick",0,2,"Left/Right,Up/Down");
+    la_AddAxisProp(pc,"ball","Ball","Ball stick",2,2,"Left/Right,Up/Down");
+    la_AddAxisProp(pc,"rudder","Rudder","Ruder twist",4,0,0);
+    la_AddAxisProp(pc,"pov","POV","POV hat",5,2,"Left/Right,Up/Down");
+    la_AddButtonProp(pc,"trigger","Trigger","Trigger", 0,0,0);
+    la_AddButtonProp(pc,"ba","A","Button A", 1,0,0);
+    la_AddButtonProp(pc,"bb","B","Button B (Side of stick)", 2,0,0);
+    la_AddButtonProp(pc,"bball","BP","Ball push", 3,0,0);  la_AddButtonProp(pc,"bc","BC","Button C (ball push)", 3,0,0);
+    la_AddButtonProp(pc,"pinky","PK","Pinky small button", 4,0,0); la_AddButtonProp(pc,"bd","BD","Button D pinky small button", 4,0,0);
+    la_AddButtonProp(pc,"pinkyl","PKL","Pinky lever", 5,0,0);
+    la_AddButtonProp(pc,"h1","H1","Hat 1 (Upper round hat)", 6,4,"N,E,S,W");
+    la_AddButtonProp(pc,"h2","H2","Hat 2 (lower jagged hat)", 10,4,"N,E,S,W");
+    //button 14-16 not sure where it is....
+}
+
+
+void laui_X56Throttle(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil),*cl, *cr, *crl,*crr, *rc, *vc, *rcl,*rcr;
+    laSplitColumn(uil,c,0.17); cl=laLeftColumn(c,0); cr=laRightColumn(c,0);
+    laSplitColumn(uil,cr,0.4); crl=laLeftColumn(cr,0); crr=laRightColumn(cr,0);
+    laSplitColumn(uil,crr,0.6); rc=laLeftColumn(crr,10); vc=laRightColumn(crr,0);
+    laSplitColumn(uil,rc,0.4); rcl=laLeftColumn(rc,2); rcr=laRightColumn(rc,0);
+    laUiItem* b,*ui,*g; laUiList*gu;
+
+    laShowItem(uil,c,This,"base.name")->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,c,This,"base.path")->Flags|=LA_TEXT_ALIGN_CENTER;
+
+    laShowItem(uil,cl,This,"pinky_up");
+    laShowItem(uil,cl,This,"pinky_dn");
+    laShowSeparator(uil,cl);
+    laShowItem(uil,cl,This,"dial_fwd");
+    laShowItem(uil,cl,This,"dial_back");
+
+    b=laBeginRow(uil,crl,0,0);
+    ui=laShowItem(uil,crl,This,"bi");ui->Expand=1;
+    ui=laShowItem(uil,crl,This,"bh");ui->Expand=1;
+    laEndRow(uil,b);
+    b=laBeginRow(uil,crl,0,0);
+    ui=laShowItem(uil,crl,This,"thr1");ui->Expand=1;ui->Extra->HeightCoeff=10;ui->Flags|=LA_UI_FLAGS_TRANSPOSE;
+    ui=laShowItem(uil,crl,This,"thr2");ui->Expand=1;ui->Extra->HeightCoeff=10;ui->Flags|=LA_UI_FLAGS_TRANSPOSE;
+    laEndRow(uil,b);
+
+    laShowItem(uil,rcl,This,"bf");
+    laShowItem(uil,rcr,This,"wf");
+    laShowItem(uil,rcl,This,"bg");
+    laShowItem(uil,rcr,This,"wg");
+    laShowSeparator(uil,cl);
+    laShowItem(uil,rcl,This,"slider");
+    laShowSeparator(uil,rcl);
+    laShowItem(uil,rcl,This,"be");
+    laShowItem(uil,rcl,This,"bball");
+    laShowItem(uil,rcr,This,"ball");
+
+    laShowItem(uil,rc,This,"h3")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+    laShowItem(uil,rc,This,"h4")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+    
+    laShowItem(uil,vc,This,"t4_up");
+    laShowItem(uil,vc,This,"t4_dn"); laShowSeparator(uil,vc);
+    laShowItem(uil,vc,This,"t3_up");
+    laShowItem(uil,vc,This,"t3_dn"); laShowSeparator(uil,vc);
+    laShowItem(uil,vc,This,"t2_up");
+    laShowItem(uil,vc,This,"t2_dn"); laShowSeparator(uil,vc);
+    laShowItem(uil,vc,This,"t1_up");
+    laShowItem(uil,vc,This,"t1_dn"); laShowSeparator(uil,vc);
+
+    laShowItem(uil,vc,This,"r3");
+    laShowItem(uil,vc,This,"r4");
+
+    laShowSeparator(uil,c);
+
+    laShowLabel(uil,cl,"Mode",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,cl,This,"mode");
+
+    laShowLabel(uil,cr,"Switches",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+
+    b=laBeginRow(uil,cr,0,0);
+    laShowItem(uil,cr,This,"sw1")->Expand=1;
+    laShowItem(uil,cr,This,"sw3")->Expand=1;
+    laShowItem(uil,cr,This,"sw5")->Expand=1;
+    laEndRow(uil,b);
+    b=laBeginRow(uil,cr,0,0);
+    laShowItem(uil,cr,This,"sw2")->Expand=1;
+    laShowItem(uil,cr,This,"sw4")->Expand=1;
+    laShowItem(uil,cr,This,"sw6")->Expand=1;
+    laEndRow(uil,b);
+    
+
+}
+void laui_X56Stick(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil),*cl, *cc, *cr;
+    laSplitColumn(uil,c,0.2); cl=laLeftColumn(c,10); cr=laRightColumn(c,0);
+    laSplitColumn(uil,cr,0.8); cc=laLeftColumn(cr,0); cr=laRightColumn(cr,10);
+    
+    laShowItem(uil,c,This,"base.name")->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,c,This,"base.path")->Flags|=LA_TEXT_ALIGN_CENTER;
+
+    laShowItem(uil,cl,This,"ba");
+    laShowItem(uil,cl,This,"pov");
+
+    laShowSeparator(uil,cl);
+
+    laShowLabel(uil,cl,"Thumb",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,cl,This,"bc");
+    laShowItem(uil,cl,This,"ball");
+
+    laShowSeparator(uil,cl);
+
+    laShowLabel(uil,cl,"Pinky",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,cl,This,"pinkyl");
+    laShowItem(uil,cl,This,"pinky");
+
+
+    laShowItem(uil,cr,This,"bb");
+    laShowSeparator(uil,cr);
+
+    laShowItem(uil,cc,This,"trigger");
+    laShowItem(uil,cc,This,"stick");
+    laShowItem(uil,cc,This,"rudder");
+
+    laShowLabel(uil,cr,"H1",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,cr,This,"h1");
+
+    laShowSeparator(uil,cr);
+
+    laShowLabel(uil,cr,"H2",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+    laShowItem(uil,cr,This,"h2");
+}

+ 4341 - 0
source/lagui/la_data.c

@@ -0,0 +1,4341 @@
+#include "la_5.h"
+
+
+extern LA MAIN;
+
+int la_IsThisProp(laProp *p, char *id){
+    return (!strcmp(p->Identifier, id));
+}
+laProp *la_PropLookup(laListHandle *lst, char *ID){
+    laProp *p = 0, *ip;
+    if (!lst) return 0;
+    p = lstFindItem(ID, la_IsThisProp, lst);
+    if (!p) if (strSame(ID, "identifier")){
+            for (ip = lst->pFirst; ip; ip = ip->Item.pNext){
+                if (ip->Tag & LA_AS_IDENTIFIER) return ip;
+            }
+        }
+    return p;
+}
+laProp *la_PropLookupIdentifierItem(laListHandle *lst){
+    laProp *p;
+    if (!lst) return 0;
+
+    for (p = lst->pFirst; p; p = p->Item.pNext){
+        if (p->Tag & LA_AS_IDENTIFIER) return p;
+        elif (la_IsThisProp(p, "identifier")) return p;
+    }
+    return 0;
+}
+
+int la_IsThisContainer(laPropContainer *p, char *id){
+    return (!strcmp(p->Identifier, id));
+}
+laPropContainer *la_ContainerLookup(char *ID){
+    laPropContainer* pc= lstFindItem(ID, la_IsThisContainer, &MAIN.PropContainers);
+    return pc;
+}
+
+void la_CopyPropPack(laPropPack* From, laPropPack* To) {
+	laPropStep* ps,*fps,*LastPs=0;
+	To->RawThis = From->RawThis;
+	To->EndInstance = From->EndInstance;
+
+	la_FreePropStepCache(To->Go);
+	To->Go = To->LastPs = 0;
+
+	for (fps = From->Go; fps; fps = fps->pNext) {
+		ps = memAcquireSimple(sizeof(laPropStep));
+		ps->p = fps->p;
+		ps->UseInstance = fps->UseInstance;
+		ps->Type = fps->Type;
+		if (LastPs)LastPs->pNext = ps;
+		else {
+			To->Go = ps;
+		}
+		LastPs = ps;
+	}
+    if(!LastPs){ To->LastPs = From->LastPs; }
+    else{ To->LastPs =LastPs; }
+}
+
+laListHandle* laGetUserList(void* HyperUserMem, laProp* Which, int* IsLocal){
+    laListHandle* users;
+    if(Which){
+        laPropContainer* pc=Which->Container;
+        if(pc->OtherAlloc || !pc->Hyper){
+            *IsLocal=1;
+            return &pc->LocalUsers;
+        }
+    }
+    *IsLocal=0;
+    return memGetUserList(HyperUserMem);
+}
+
+laItemUserLinker *laUseDataBlock(void *HyperUserMem, laProp *Which, unsigned int FrameDistinguish, void *User, laUserRemoveFunc Remover, int ForceRecalc){
+    laItemUserLinker *iul; laItemUserLinkerLocal *iull; int local;
+    if (!HyperUserMem) return;
+    laListHandle* users = laGetUserList(HyperUserMem, Which, &local); if(!users) return;
+    for (iul = users->pFirst; iul; iul = iul->Pointer.pNext){
+        if(local && (iull=iul) && iull->Instance!=HyperUserMem) continue;
+        if (iul->Which == Which && iul->Pointer.p == User){
+            iul->FrameDistinguish = FrameDistinguish;
+            if(ForceRecalc) iul->ForceRecalc = ForceRecalc;
+            return iul;
+        }
+    }
+    iul = lstAppendPointerSized(users, User, local?sizeof(laItemUserLinkerLocal):sizeof(laItemUserLinker));
+    iul->Which = Which;
+    iul->FrameDistinguish = FrameDistinguish;
+    iul->Remove = Remover;
+    iul->ForceRecalc = ForceRecalc;
+    if(local){ iull=iul; iull->Instance=HyperUserMem; }
+    return iul;
+}
+void laStopUsingDataBlock(void *HyperUserMem, laProp *prop, laPanel* p){
+    laItemUserLinker *iul,*next_iul; laItemUserLinkerLocal *iull; int local;
+    if (!HyperUserMem) return;
+    laListHandle* users = laGetUserList(HyperUserMem, prop, &local); if(!users) return;
+    for (iul = users->pFirst; iul; iul = next_iul){
+        next_iul = iul->Pointer.pNext;
+        if(local && (iull=iul) && iull->Instance!=HyperUserMem) continue;
+        if (/*prop == iul->Which &&*/ iul->Pointer.p == p){
+            lstRemoveItem(users,iul);
+            memFree(iul);
+        }
+    }
+}
+void laDataBlockNoLongerExists(void *HyperUserMem, laListHandle* UserList){
+    laItemUserLinker *iul,*next_iul;
+    for (iul = UserList->pFirst; iul; iul = next_iul){
+        next_iul = iul->Pointer.pNext;
+        iul->Remove(HyperUserMem, iul);
+        lstRemoveItem(UserList,iul);
+        memFree(iul);
+    }
+}
+
+//laProp* la_GetGeneralPropFromPath(laProp* General, const char * Path) {
+//	laProp* p;
+//	laListHandle* lst = &General->Sub;
+//	laStringSplitor* ss = strSplitPathByDot(Path);
+//	laStringPart* sp = ss->parts.pFirst;
+//
+//	while (sp) {
+//		p = la_PropLookup(lst, sp->Content);
+//		lst = &p->Sub;
+//		sp = sp->Item.pNext;
+//	}
+//
+//	strDestroyStringSplitor(&ss);
+//	return p;
+//}
+
+//laProp* la_GetPropFromPath(laPropPack* Base,const char * Path) {
+//	laProp* p,*LastP=Base?Base->P:0;
+//	laListHandle* lst;
+//	laStringSplitor* ss = strSplitPathByDot(Path);
+//	laStringPart* sp = ss->parts.pFirst;
+//
+//	if(!Base || !Base->P)
+//		lst = &MAIN.DataRoot.Root->Sub;
+//	else lst = &Base->P->Sub;
+//
+//
+//	while (sp) {
+// 		p = la_PropLookup(lst, sp->Content);
+//		if (!p && LastP) {
+//			p = la_PropLookup(&la_GetGeneralProp(LastP)->Sub, sp->Content);
+//		}
+//		LastP = p;
+//		lst = &p->Sub;
+//		sp = sp->Item.pNext;
+//	}
+//
+//	strDestroyStringSplitor(&ss);
+//
+//	return p;
+//}
+
+void la_NewPropStep(laPropPack *Self, laProp *P, void *UseInstance, char Type){
+    laPropStep *ps = memAcquireSimple(sizeof(laPropStep));
+
+    if (Type == L'.' || Type == L'$'){
+        ps->p = P;
+        ps->UseInstance = UseInstance;
+        ps->Type = Type;
+    }elif (Type == L'@' || Type == L'=' || Type == L'#'){
+        ps->p = CreateNewBuffer(char, strlen(P) + 1);
+        strcpy(ps->p, P);
+        ps->UseInstance = UseInstance;
+        ps->Type = Type;
+    }
+
+    if (!Self->Go){
+        Self->Go = ps;
+        Self->LastPs = ps;
+    }else{
+        Self->LastPs->pNext = ps;
+        Self->LastPs = ps;
+    }
+}
+void la_FreePropStepCache(laPropStep *GoTarget){
+    if (!GoTarget) return;
+    if (GoTarget->pNext){
+        la_FreePropStepCache(GoTarget->pNext);
+    }
+    if (GoTarget->Type == L'@' || GoTarget->Type == L'=' || GoTarget->Type == L'#') FreeMem(GoTarget->p);
+    memFree(GoTarget);
+}
+void *la_FindMatchingInstance(void *From, laProp *Sub, laProp *p, laPropStep *Value){
+    laPropPack Fake;
+    laPropStep FakePs;
+    laPropIterator pi = {0};
+    void *Inst;
+    char _buf[LA_RAW_CSTR_MAX_LEN]={0}; char*buf=_buf;
+    int val;
+
+    Fake.LastPs = &FakePs;
+    FakePs.p = p;
+
+    Inst = laGetInstance(Sub, From, &pi);
+
+    if (p->PropertyType == LA_PROP_STRING){
+        _buf[0] = 0;
+        FakePs.UseInstance = Inst;
+        laGetString(&Fake, _buf, &buf);
+
+        while (!strSame(buf, Value->p)){
+            Inst = laGetNextInstance(Sub, Inst, &pi);
+            if (!Inst) return 0;
+            _buf[0] = 0;
+            FakePs.UseInstance = Inst;
+            laGetString(&Fake, _buf, &buf);
+        }
+
+        return Inst;
+    }elif (p->PropertyType == LA_PROP_INT){
+        FakePs.UseInstance = Inst;
+        val = laGetInt(&Fake);
+        while (val != Value->UseInstance){
+            Inst = laGetNextInstance(Sub, From, &pi);
+            if (!Inst) return 0;
+            FakePs.UseInstance = Inst;
+            val = laGetInt(&Fake);
+        }
+        return Inst;
+    }
+}
+int la_GetPropFromPath(laPropPack *Self, laPropPack *Base, const char *Path, void **SpecifiedInstance){
+    laProp *p = 0;
+    laListHandle *lst=0, *lstB = 0;
+    laStringSplitor *ss = strSplitPath(Path);
+    laStringPart *sp = ss ? ss->parts.pFirst : 0;
+    int InstanceNum = 0;
+
+    if ((!ss && !Base) || !MAIN.DataRoot.Root){ strDestroyStringSplitor(&ss); return 0; }
+
+    if (!Base || !Base->LastPs){
+        lst = &MAIN.DataRoot.Root->Props;
+        Self->RawThis = 0;
+    }else{
+        Self->RawThis = Base;
+        if (Base->LastPs->p->PropertyType==LA_PROP_SUB && ((laSubProp*)Base->LastPs->p)->GetType && Base->EndInstance){
+            laPropContainer* pc=((laSubProp*)Base->LastPs->p)->GetType(Base->EndInstance);
+            lst = &pc->Props;
+            lstB = pc ? &pc->Props : 0;
+        }
+        if(!lst){
+            if (!Base->LastPs->p->SubProp){
+                laProp *p = Base->LastPs->p;
+                p->SubProp = la_ContainerLookup(((laSubProp *)p)->TargetID);
+            }
+            if(Base->LastPs->p->SubProp) lst = &Base->LastPs->p->SubProp->Props;
+        }
+        lstB = Base->LastPs->p->SubExtra ? &Base->LastPs->p->SubExtra->Props : 0;
+
+        if (!Path || !Path[0] || !ss){
+            if (Base){
+                Self->LastPs = Base->LastPs;
+            }
+        }
+    }
+    while (sp){
+        if (sp->Type == L'.' || sp->Type == L'$'){
+            void *inst = 0;
+            p = la_PropLookup(lst, sp->Content); 
+            if (!p) p = la_PropLookup(lstB, sp->Content);
+            if (!p){
+                la_FreePropStepCache(Self->Go);
+                Self->Go = Self->LastPs = 0;
+                strDestroyStringSplitor(&ss);
+                return 0; //          |-----------------Here Should Include Dollar Instance
+            }             //                      V
+            if (sp->Type == L'$'){
+                inst = SpecifiedInstance[InstanceNum];
+                InstanceNum++;
+            }else
+                inst = 0;
+            /*if(Base == &MAIN.PropMatcherContextP->PropLinkPP)la_NewPropStep(Self, p, inst, '*');
+			else */
+            la_NewPropStep(Self, p, inst, sp->Type);
+            if (p->PropertyType == LA_PROP_SUB && !p->SubProp){
+                p->SubProp = la_ContainerLookup(((laSubProp *)p)->TargetID);
+            }
+            lst = p->SubProp ? &p->SubProp->Props : 0;
+            lstB = p->SubExtra ? &p->SubExtra->Props : 0;
+        }else{
+            if (sp->Type == L'@' || sp->Type == L'=' || sp->Type == L'#'){ // || sp->Type== L'~'
+                la_NewPropStep(Self, sp->Content, sp->IntValue, sp->Type);
+            }
+        }
+        sp = sp->Item.pNext;
+    }
+
+    strDestroyStringSplitor(&ss);
+
+    return 1;
+}
+void la_StepPropPack(laPropPack *pp){
+    laPropStep *ps = pp->Go;
+    laPropPack *This = pp->RawThis;
+    laPropIterator pi;
+    laProp *Lookup;
+    laPropStep *Value;
+    void *UseInstance = 0;
+
+    if (This){
+        UseInstance = This->EndInstance;
+        if (ps) ps->UseInstance = UseInstance;
+    }else{
+        if (!ps) return;
+        UseInstance = MAIN.DataRoot.RootInstance;
+        ps->UseInstance = UseInstance;
+    }
+
+    if (This && !ps){
+        pp->EndInstance = UseInstance;
+        pp->LastPs = This->LastPs;
+        return;
+    }
+
+    while (ps){
+        // Looks like we have these kind of access grammar:
+        // sub.prop
+        // sub@prop=str_or_int
+        // sub#identifier
+        // TODO: Add sub~index grammar
+        if (ps->p->PropertyType == LA_PROP_SUB){
+            if (ps->Type == L'@' || ps->Type == L'#'){
+            }
+            if (ps->Type == L'$') UseInstance = ps->UseInstance;
+            elif (ps->pNext && ps->pNext->Type != L'.'){
+                if (ps->pNext->Type == L'@'){
+                    Value = ps->pNext->pNext;
+                    Lookup = la_PropLookup(&ps->p->SubProp->Props, ps->pNext->p);
+                }elif (ps->pNext->Type == L'#'){
+                    Value = ps->pNext;
+                    Lookup = la_PropLookupIdentifierItem(&ps->p->SubProp->Props);
+                }
+                if (Value->Type == L'=' || Value->Type == L'#'){ //MUST!
+                    UseInstance = la_FindMatchingInstance(ps->UseInstance, ps->p, Lookup, Value);
+                }
+                Value->UseInstance = UseInstance;
+                if(Value->pNext) Value->pNext->UseInstance = UseInstance;
+                ps = Value->pNext;
+                continue;
+            }else{
+                void *inst;
+                inst = laGetActiveInstanceStrict(ps->p, UseInstance);
+                if (!inst) inst = laGetInstance(ps->p, UseInstance, 0);
+                UseInstance = inst;
+            }
+            if (!ps->pNext){
+                pp->EndInstance = UseInstance;
+                break;
+            }else{
+                ps->pNext->UseInstance = UseInstance;
+                ps = ps->pNext;
+            }
+            continue;
+        }else{
+            ps->UseInstance = UseInstance;
+            if (!ps->pNext){
+                pp->EndInstance = UseInstance;
+                break;
+            }else{
+                ps->pNext->UseInstance = ps;
+                UseInstance = ps;
+                ps = ps->pNext;
+            }
+        }
+    }
+}
+
+void la_RemovePropUserNode(laPropStep *ps){
+    laPropUserPanel *pup = 0;
+    laPropUser *pu = 0;
+    for (pup = ps->p->UserPanels.pFirst; pup; pup = pup->Item.pNext){
+        if (pup->Panel == MAIN.PropMatcherContextP) break;
+    }
+    if (!pup) return;
+    for (pu = pup->UserPacks.pFirst; pu; pu = pu->Item.pNext){
+        if (pu->User == ps) break;
+    }
+    //if (!pu)printf("PROP USER NODE NOT FOUND!\laPropUserPanel:%d,%s,Ps:%s\n",pup->Panel,pup->Panel->Title->Ptr,ps->p->Identifier);
+    //else {
+    if (pu){
+        lstRemoveItem(&pup->UserPacks, pu);
+        memFree(pu);
+        if (!pup->UserPacks.pFirst){
+            lstRemoveItem(&ps->p->UserPanels, pup);
+            memFree(pup);
+        }
+    }
+    //}
+}
+void la_AddPropUserNode(laPropStep *ps){
+    laPropUserPanel *pup = 0;
+    laPropUser *pu = 0;
+    for (pup = ps->p->UserPanels.pFirst; pup; pup = pup->Item.pNext){
+        if (pup->Panel == MAIN.PropMatcherContextP) break;
+    }
+    if (!pup){
+        pup = memAcquireSimple(sizeof(laPropUserPanel));
+        pup->Panel = MAIN.PropMatcherContextP;
+        lstAppendItem(&ps->p->UserPanels, pup);
+    }
+    for (pu = pup->UserPacks.pFirst; pu; pu = pu->Item.pNext){
+        if (pu->User == ps){
+            pu->FrameDistinguish = MAIN.PropMatcherContextP->FrameDistinguish;
+            return;
+        }
+    }
+    //ELSE
+    pu = memAcquireSimple(sizeof(laPropUser));
+    pu->User = ps;
+    pu->FrameDistinguish = MAIN.PropMatcherContextP->FrameDistinguish;
+    lstAppendItem(&pup->UserPacks, pu);
+}
+void la_UsePropPack(laPropPack *pp, int ForceRecalc){
+    laPropStep *ps = 0;
+    //return;
+    if((!pp->Go) && pp->LastPs){
+        if (pp->LastPs->Type==L'.'){
+            laUseDataBlock(pp->RawThis->LastPs->UseInstance, pp->LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, ForceRecalc);
+        }
+    }
+    for (ps = pp->Go; ps; ps = ps->pNext){
+        if (ps->Type==L'.'){ printf("%s ", ps->p->Identifier);
+            laUseDataBlock(ps->UseInstance, ps->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, ForceRecalc);
+        }
+    }printf("\n");
+}
+void la_StopUsingPropPack(laPropPack *pp){
+    laPropStep *ps;
+    if((!pp->Go) && pp->LastPs){
+        if (pp->LastPs->Type==L'.'&&pp->LastPs->p->Container &&pp->LastPs->p->Container->Hyper){
+            laStopUsingDataBlock(pp->RawThis->LastPs->UseInstance, pp->LastPs->p, MAIN.PropMatcherContextP);
+        }
+    }
+    for (ps = pp->Go; ps; ps = ps->pNext){
+        if (ps->Type==L'.'&&ps->p->Container&&ps->p->Container->Hyper){
+            laStopUsingDataBlock(ps->UseInstance, ps->p, MAIN.PropMatcherContextP);
+        }
+        //la_RemovePropUserNode(ps);
+    }
+}
+
+void laNotifyUsersPP(laPropPack *pp){
+    if(!pp->LastPs) return;
+    void *hi = pp->LastPs->UseInstance;
+    laItemUserLinker *iul; laItemUserLinkerLocal *iull; int local;
+    if (!hi) return;
+    laListHandle* users = laGetUserList(hi, pp->LastPs->p, &local); if(!users) return;
+    for (iul = users->pFirst; iul; iul = iul->Pointer.pNext){
+        if(local && (iull=iul) && iull->Instance!=hi) continue;
+        if (iul->Remove == la_PropPanelUserRemover){
+            laPanel *p = iul->Pointer.p;
+            if (iul->Which == pp->LastPs->p && iul->FrameDistinguish == p->FrameDistinguish){
+                //pthread_spin_lock(&MAIN.csNotifier);
+                if (iul->Which->PropertyType & LA_PROP_SUB || iul->ForceRecalc) p->Refresh |= LA_TAG_RECALC;
+                else
+                    p->Refresh |= LA_TAG_REDRAW;
+                //pthread_spin_unlock(&MAIN.csNotifier);
+            }
+        }
+    }
+}
+void laNotifyUsersPPPath(laPropPack *pp, char *path){
+    laPropPack PP = {0};
+    if(!path){ laNotifyUsersPP(pp); return; }
+    la_GetPropFromPath(&PP, pp, path, 0);
+    la_StepPropPack(&PP);
+    laNotifyUsersPP(&PP);
+    la_FreePropStepCache(PP.Go);
+}
+void laNotifySubPropUsers(laProp *prop, void *Instance){
+    void *hi = Instance;
+    laItemUserLinker *iul; laItemUserLinkerLocal *iull; int local;
+    if (!hi) return;
+    laListHandle* users = laGetUserList(hi, prop, &local); if(!users) return;
+    for (iul = users->pFirst; iul; iul = iul->Pointer.pNext){
+        if(local && (iull=iul) && iull->Instance!=hi) continue;
+        if (iul->Remove == la_PropPanelUserRemover){
+            laPanel *p = iul->Pointer.p;
+            if (iul->Which == prop && iul->FrameDistinguish == p->FrameDistinguish){
+                //pthread_spin_lock(&MAIN.csNotifier);
+                p->Refresh |= LA_TAG_RECALC;
+                //pthread_spin_unlock(&MAIN.csNotifier);
+            }
+        }
+    }
+}
+void laNotifyUsers(char *Path){
+    laPropPack PP = {0};
+    la_GetPropFromPath(&PP, 0, Path, 0);
+    la_StepPropPack(&PP);
+    laNotifyUsersPP(&PP);
+    la_FreePropStepCache(PP.Go);
+}
+void laThreadNotifyUsers(char *Path){
+    laThreadNotifier *tn = CreateNew(laThreadNotifier);
+    strCopyFull(tn->Path, Path);
+
+    //pthread_spin_lock(&MAIN.csNotifier);
+    lstAppendItem(&MAIN.ThreadNotifiers, tn);
+    //pthread_spin_unlock(&MAIN.csNotifier);
+}
+
+void la_SetPropMathcerContext(laPanel *p){
+    MAIN.PropMatcherContextP = p;
+}
+
+int laget_InstanceHyperLevel(void* instance){
+    int level; memGetHead(instance,&level);
+    return level;
+}
+int laget_InstanceModified(void* instance){
+    int level; laMemNodeHyper* m=memGetHead(instance,&level);
+    if(level==2) return m->Modified?1:0;
+    return 0;
+}
+void* laget_InstanceUDF(void* unused, laPropIterator* unusedpi){
+    return MAIN.ManagedUDFs.pFirst;
+}
+void* laget_InstanceActiveUDF(void* instance){
+    int level; laMemNodeHyper* m=memGetHead(instance,&level);
+    if(level==2) return m->FromFile;
+    return 0;
+}
+void laset_InstanceUDF(void* instance, void* set){
+    int level; laMemNodeHyper* m=memGetHead(instance,&level);
+    if(level==2) memAssignRef(instance, &m->FromFile, set);
+    if(set == MAIN.DummyManageUDF){
+        laInvoke(0, "LA_managed_save_new_file", 0,0,0,0);
+    }
+}
+void* laget_InstanceSelf(void* instace){
+    return instace;
+}
+const char* LA_N_A="N/A";
+void laget_InstanceUID(void* instance, char* buf, char** ptr){
+    int level; laMemNodeHyper* m=memGetHead(instance,&level);
+    if(level!=2||!m) return; *ptr=LA_N_A;
+    *ptr=m->NUID.String;
+}
+void laset_InstanceUID(void* instance, char* buf){
+    int level; laMemNodeHyper* m=memGetHead(instance,&level);
+    if(level!=2||!m) return;
+    if(!buf[0]) memCreateNUID(m);
+    sprintf(m->NUID.String,"%.30s",buf);
+}
+void la_FreeProperty(laProp* p){
+    laIntProp *ip;laFloatProp *fp;laEnumProp *ep;laSubProp *sp;
+    if(p->DetachedPP.Go){
+        la_FreePropStepCache(p->DetachedPP.Go);
+        switch (p->PropertyType){
+        case LA_PROP_INT:
+        case LA_PROP_INT | LA_PROP_ARRAY:
+            ip = p; free(ip->Detached);
+            break;
+        case LA_PROP_FLOAT:
+        case LA_PROP_FLOAT | LA_PROP_ARRAY:
+            fp = p; free(fp->Detached);
+            break;
+        case LA_PROP_ENUM:
+        case LA_PROP_ENUM | LA_PROP_ARRAY:
+            ep = p; free(ep->Detached);
+        }
+    }
+    if(p->PropertyType&LA_PROP_ENUM){ ep = p; laEnumItem* ei;  while(ei=lstPopItem(&ep->Items)){ memFree(ei); } }
+    memFree(p);
+}
+void la_FreePropertyContainer(laPropContainer* pc){
+    laProp* p;
+    while(p=lstPopItem(&pc->Props)){
+        la_FreeProperty(p);
+    }
+    memFree(pc);
+}
+laPropContainer *laAddPropertyContainer(const char *Identifier, const char *Name, const char *Description, uint32_t IconID,
+                                        laUiDefineFunc DefaultUiDefine,
+                                        int NodeSize, laContainerPostReadFunc PostRead, laContainerPostReadFunc PostReadIm, int IsHyper){
+
+    laPropContainer *pc = memAcquire(sizeof(laPropContainer));
+    pc->Identifier = Identifier;
+    pc->Name = Name;
+    pc->Description = Description;
+    pc->UiDefine = DefaultUiDefine;
+    pc->IconID = IconID ? IconID : L'📦';
+
+    pc->OtherAlloc = (IsHyper&LA_PROP_OTHER_ALLOC)?1:0;
+    pc->Hyper = pc->OtherAlloc?0:(IsHyper&LA_PROP_HYPER_BITS);
+    pc->PostRead = PostRead;
+    pc->PostReadIm = PostReadIm;
+    pc->NodeSize = NodeSize;
+
+    if (!pc->OtherAlloc){
+        laAddSubGroup(pc, "__file", "File", "The file this block came from/saves to", "managed_udf",
+            0,LA_WIDGET_COLLECTION_SELECTOR,laui_ManagedUDFItem,-1,laget_InstanceUDF,laget_InstanceActiveUDF,laget_ListNext,laset_InstanceUDF,0,0,0,LA_UDF_REFER|LA_UDF_IGNORE);
+        laAddIntProperty(pc, "__hyper", "Hyper", "Hyper level of this data block", 0,0,0,0,0,0,0,0,-1,laget_InstanceHyperLevel,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+        laProp* p=laAddEnumProperty(pc, "__modified", "Modified", "Data block is modified", LA_WIDGET_ENUM_ICON_PLAIN,0,0,0,0,-1,laget_InstanceModified,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+        laAddEnumItemAs(p, "MODIFIED", "Modified", "Data block is modified", 1, L'🌑');
+        laAddEnumItemAs(p, "CLEAN", "Clean", "Data block is clean", 0, 0);
+        laAddStringProperty(pc, "__uid","UID","UID for shared resoure lookup",0,0,0,0,0,-1,0,laget_InstanceUID,laset_InstanceUID,0,0);
+    }
+
+    laAddSubGroup(pc, "__self", "Self", "Own instance", Identifier,0,0,0,-1,0,laget_InstanceSelf,0,0,0,0,0,LA_UDF_REFER|LA_UDF_IGNORE);   
+
+    lstAppendItem(&MAIN.PropContainers, pc);
+
+    return pc;
+}
+void laPropContainerExtraFunctions(laPropContainer* pc, laContainerBeforeFreeF BeforeFree, laContainerUndoTouchedF Touched, laContainerpUDFPropagateF UDFPropagate){
+    pc->BeforeFree=BeforeFree; pc->UndoTouched=Touched; pc->UDFPropagate=UDFPropagate;
+    if(!pc->OtherAlloc && UDFPropagate){
+        laAddOperatorProperty(pc,"__udf_propagate","Propagate","Propagate UDF to all child nodes", "LA_udf_propagate", 0,0);
+    }
+}
+
+int la_GetPropertySize(int Type){
+    switch (Type){
+    case LA_PROP_INT:
+    case LA_PROP_INT | LA_PROP_ARRAY:
+        return sizeof(laIntProp);
+    case LA_PROP_FLOAT:
+    case LA_PROP_FLOAT | LA_PROP_ARRAY:
+        return sizeof(laFloatProp);
+    case LA_PROP_ENUM:
+    case LA_PROP_ENUM | LA_PROP_ARRAY:
+        return sizeof(laEnumProp);
+    case LA_PROP_SUB: return sizeof(laSubProp);
+    case LA_PROP_OPERATOR: return sizeof(laOperatorProp);
+    case LA_PROP_STRING: return sizeof(laStringProp);
+    case LA_PROP_RAW: return sizeof(laRawProp);
+    }
+    return 0;
+}
+const char LA_PROP_STR_INT[] = "LA_PROP_INT";
+const char LA_PROP_STR_INT_ARR[] = "LA_PROP_INT_ARR";
+const char LA_PROP_STR_FLOAT[] = "LA_PROP_FLOAT";
+const char LA_PROP_STR_FLOAT_ARR[] = "LA_PROP_FLOAT_ARR";
+const char LA_PROP_STR_ENUM[] = "LA_PROP_ENUM";
+const char LA_PROP_STR_ENUM_ARR[] = "LA_PROP_ENUM_ARR";
+const char LA_PROP_STR_ACT[] = "LA_PROP_ACT";
+const char LA_PROP_STR_STR[] = "LA_PROP_STR";
+const char LA_PROP_STR_SUB[] = "LA_PROP_SUB";
+
+const char *la_GetPropertyTypeString(int Type){
+    switch (Type){
+    case LA_PROP_INT:
+        return LA_PROP_STR_INT;
+    case LA_PROP_INT | LA_PROP_ARRAY:
+        return LA_PROP_STR_INT_ARR;
+    case LA_PROP_FLOAT:
+        return LA_PROP_STR_FLOAT;
+    case LA_PROP_FLOAT | LA_PROP_ARRAY:
+        return LA_PROP_STR_FLOAT_ARR;
+    case LA_PROP_ENUM:
+        return LA_PROP_STR_ENUM;
+    case LA_PROP_ENUM | LA_PROP_ARRAY:
+        return LA_PROP_STR_ENUM_ARR;
+    case LA_PROP_SUB:
+        return LA_PROP_STR_SUB;
+    case LA_PROP_OPERATOR:
+        return LA_PROP_STR_ACT;
+    case LA_PROP_STRING:
+        return LA_PROP_STR_STR;
+    }
+    return 0;
+}
+
+void la_AssignPropertyGeneralSub(laProp *p){
+    switch (p->PropertyType){
+    case LA_PROP_INT: p->SubProp = MAIN.GeneralIntSub; break;
+    case LA_PROP_INT | LA_PROP_ARRAY: p->SubProp = MAIN.GeneralIntArraySub;  break;
+    case LA_PROP_FLOAT: p->SubProp = MAIN.GeneralFloatSub; break;
+    case LA_PROP_FLOAT | LA_PROP_ARRAY: p->SubProp = MAIN.GeneralFloatArraySub; break;
+    case LA_PROP_ENUM: p->SubProp = MAIN.GeneralEnumSub; break;
+    case LA_PROP_ENUM | LA_PROP_ARRAY: p->SubProp = MAIN.GeneralEnumArraySub; break;
+    case LA_PROP_STRING: p->SubProp = MAIN.GeneralStringSub; break;
+    case LA_PROP_OPERATOR: p->SubProp = MAIN.GeneralOperatorSub; break;
+    case LA_PROP_SUB: p->SubExtra = MAIN.GeneralCollectionSub; break;
+    case LA_PROP_RAW: p->SubExtra = MAIN.GeneralRawSub; break;
+    }
+}
+
+laProp *la_CreateProperty(laPropContainer *Container, int Type, const char *Identifier, const char *Name, const char *Description,
+                          const char *Prefix, const char *Unit, laWidget* DefaultWidget, u64bit Tag){
+    laProp *p = memAcquire(la_GetPropertySize(Type));
+
+    p->Identifier = Identifier;
+    p->Name = Name;
+    p->Description = Description;
+    p->Prefix = Prefix;
+    p->Unit = Unit;
+    if(DefaultWidget){ p->DefaultUiType = DefaultWidget->Type; p->DefaultFlags = DefaultWidget->Flags; }
+    p->PropertyType = Type;
+    p->Tag = Tag;
+    p->Container = Container;
+
+    if (Container) lstAppendItem(&Container->Props, p);
+
+    p->UDFIsRefer = (Tag & LA_UDF_REFER) ? 1 : 0;
+    p->UDFIgnore = (Tag & LA_UDF_IGNORE) ? 1 : 0;
+    p->UDFOnly = (Tag & LA_UDF_ONLY) ? 1 : 0;
+    p->ReadOnly = (Tag & LA_READ_ONLY) ? 1 : 0;
+
+    return p;
+}
+
+laProp *la_MakeDetachedProp(laPanel* p, const char *From, const char *Rename){
+    laIntProp *ip;
+    laFloatProp *fp;
+    laEnumProp *ep;
+    laSubProp *sp;
+
+
+    laPropPack TempPP = {0};
+    int result = 0;
+
+    result = la_GetPropFromPath(&TempPP, 0, From, 0);
+    if(!result) return 0;
+    
+    laProp *np = CreateNew_Size(la_GetPropertySize(TempPP.LastPs->p->PropertyType));
+    memcpy(np, TempPP.LastPs->p, la_GetPropertySize(TempPP.LastPs->p->PropertyType));
+
+    np->Identifier = CreateNewBuffer(char, 128);
+    strcpy(np->Identifier, Rename);
+    np->DetachedPP.Go = 0;
+    np->DetachedPP.RawThis = 0;
+    np->DetachedPP.LastPs = 0;
+    la_CopyPropPack(&TempPP, &np->DetachedPP);
+
+    switch (np->PropertyType){
+    case LA_PROP_INT:
+    case LA_PROP_INT | LA_PROP_ARRAY:
+        ip = np;
+        ip->Detached = CreateNewBuffer(int, np->Len ? np->Len : 1);
+        break;
+    case LA_PROP_FLOAT:
+    case LA_PROP_FLOAT | LA_PROP_ARRAY:
+        fp = np;
+        fp->Detached = CreateNewBuffer(real, np->Len ? np->Len : 1);
+        break;
+    case LA_PROP_ENUM:
+    case LA_PROP_ENUM | LA_PROP_ARRAY:
+        ep = np;
+        ep->Detached = CreateNewBuffer(int, 1);
+        ep->Detached[0] = ((laEnumItem *)ep->Items.pFirst)->Index;
+    }
+    lstAppendItem(&p->PropLinkContainer->Props, np);
+    la_AssignPropertyGeneralSub(np);
+    la_FreePropStepCache(TempPP.Go);
+    return np;
+}
+laProp *laAddIntProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                         const char *Prefix, const char *Unit, int Max, int Min, int Step, int DefVal, const int *DefArr,
+                         int OffsetSize, laIntGetF Get, laIntSetF Set, int ArrayLength, laArrayGetLenF GetLen,
+                         laIntArraySetF SetArr, laIntArrayGetAllF GetAll, laIntArraySetAllF SetAll, laIntArraySetAllArrayF SetAllArr,
+                         laIntReadF Read, laIntArrayReadAllF ReadAll,
+                         u64bit Tag){
+
+    laIntProp *p = la_CreateProperty(Container, LA_PROP_INT, Identifier, Name, Description, Prefix, Unit, DefaultWidget, Tag);
+
+    if (ArrayLength > 1){
+        p->Base.Len = ArrayLength;
+        p->Base.PropertyType |= LA_PROP_ARRAY;
+    }else if (GetLen)
+        p->Base.GetLen = GetLen;
+
+    p->Get = Get;
+    p->Set = Set;
+    p->SetAll = SetAll;
+    p->GetAll = GetAll;
+    p->SetAllArr = SetAllArr;
+    p->SetArr = SetArr;
+    p->DefArr = DefArr;
+    p->DefVal = DefVal;
+    p->Max = Max;
+    p->Min = Min;
+    p->Step = Step ? Step : 1;
+    p->Base.Offset = OffsetSize;
+    p->Base.OffsetIsPointer = (Tag&LA_UDF_REFER) ? 1 : 0;
+
+    p->Read = Read;
+    p->ReadAll = ReadAll;
+
+    la_AssignPropertyGeneralSub(p);
+
+    return p;
+}
+
+laProp *laAddFloatProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                           const char *Prefix, const char *Unit, real Max, real Min, real Step, real DefVal, const real *DefArr,
+                           int OffsetSize, laFloatGetF Get, laFloatSetF Set, int ArrayLength, laArrayGetLenF GetLen,
+                           laFloatArraySetF SetArr, laFloatArrayGetAllF GetAll, laFloatArraySetAllF SetAll, laFloatArraySetAllArrayF SetAllArr,
+                           laFloatReadF Read, laFloatArrayReadAllF ReadAll,
+                           u64bit Tag){
+
+    laFloatProp *p = la_CreateProperty(Container, LA_PROP_FLOAT, Identifier, Name, Description, Prefix, Unit, DefaultWidget, Tag);
+
+    if (ArrayLength > 1){
+        p->Base.Len = ArrayLength;
+        p->Base.PropertyType |= LA_PROP_ARRAY;
+    }else if (GetLen)
+        p->Base.GetLen = GetLen;
+
+    p->Get = Get;
+    p->Set = Set;
+    p->SetAll = SetAll;
+    p->GetAll = GetAll;
+    p->SetAllArr = SetAllArr;
+    p->SetArr = SetArr;
+    p->DefArr = DefArr;
+    p->DefVal = DefVal;
+    p->Max = Max;
+    p->Min = Min;
+    p->Step = Step ? Step : 0.01;
+
+    p->Base.Offset = OffsetSize;
+    p->Base.OffsetIsPointer = (Tag&LA_UDF_REFER) ? 1 : 0;
+
+    p->Read = Read;
+    p->ReadAll = ReadAll;
+
+    la_AssignPropertyGeneralSub(p);
+
+    return p;
+}
+
+laProp *laAddEnumProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                          const char *Prefix, const char *Unit, int DefVal, const int *DefArr,
+                          int OffsetSize, laEnumGetF Get, laEnumSetF Set, int ArrayLength, laArrayGetLenF GetLen,
+                          laEnumArraySetF SetArr, laEnumArrayGetAllF GetAll, laEnumArraySetAllF SetAll,
+                          laEnumReadF Read, laEnumArrayReadAllF ReadAll,
+                          u64bit Tag){
+
+    laEnumProp *p = la_CreateProperty(Container, LA_PROP_ENUM, Identifier, Name, Description, Prefix, Unit, DefaultWidget, Tag);
+
+    if (ArrayLength > 1){
+        p->Base.Len = ArrayLength;
+        p->Base.PropertyType |= LA_PROP_ARRAY;
+    }else if (GetLen)
+        p->Base.GetLen = GetLen;
+
+    p->Get = Get;
+    p->Set = Set;
+    p->SetAll = SetAll;
+    p->GetAll = GetAll;
+    p->SetArr = SetArr;
+    p->DefArr = DefArr;
+    p->DefVal = DefVal;
+
+    p->Base.Offset = OffsetSize;
+    p->Base.OffsetIsPointer = (Tag&LA_UDF_REFER) ? 1 : 0;
+
+    p->Read = Read;
+    p->ReadAll = ReadAll;
+
+    la_AssignPropertyGeneralSub(p);
+
+    return p;
+}
+
+int laAddEnumItem(laProp *p, const char *Identifier, const char *Name, const char *Description, uint32_t IconID){
+    laEnumItem *ei = memAcquire(sizeof(laEnumItem));
+    laEnumProp *ep = p;
+
+    ei->Identifier = Identifier;
+    ei->Name = Name;
+    ei->Description = Description;
+    ei->IconID = IconID;
+
+    ei->Index = ep->Items.pLast ? ((laEnumItem *)ep->Items.pLast)->Index + 1 : 0;
+
+    lstAppendItem(&ep->Items, ei);
+
+    return 1;
+}
+
+int laAddEnumItemAs(laProp *p, const char *Identifier, const char *Name, const char *Description, int Index, uint32_t IconID){
+    laEnumItem *ei = memAcquire(sizeof(laEnumItem));
+    laEnumProp *ep = p;
+
+    ei->Identifier = Identifier;
+    ei->Name = Name;
+    ei->Description = Description;
+    ei->IconID = IconID;
+
+    ei->Index = Index;
+
+    lstAppendItem(&ep->Items, ei);
+
+    return 1;
+}
+
+laProp *laAddStringProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                            const char *Prefix, const char *Unit, const char *DefStr,
+                            int IsSafeString, int OffsetSize, laStringGetLenF GetLen, laStringGetF Get, laStringSetF Set,
+                            laStringReadF Read,
+                            u64bit Tag){
+
+    laStringProp *p = la_CreateProperty(Container, LA_PROP_STRING, Identifier, Name, Description, Prefix, Unit, DefaultWidget, Tag);
+
+    p->Get = Get;
+    p->Set = Set;
+    p->Getstrlen = GetLen;
+    p->DefStr = DefStr;
+    p->Base.Offset = OffsetSize;
+    p->Base.OffsetIsPointer = (Tag&LA_UDF_LOCAL) ? 0 : 1;
+    p->Read = Read;
+
+    p->IsSafeString = IsSafeString;
+
+    la_AssignPropertyGeneralSub(p);
+
+    return p;
+}
+
+laProp *laAddSubGroup(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description,
+                      const char *TargetId, laGetNodeTypeFunc GetType, laWidget* DefaultWidget, laUiDefineFunc DefaultUiDef,
+                      int OffsetSize, laSubGetInstanceF Get, laSubGetInstanceF GetActive, laSubGetNextF GetNext, laSubSetInstanceF Set,
+                      laSubGetStateF GetState, laSubSetStateF SetState, int ListHandleOffset, u64bit Tag){
+
+    laSubProp *p = la_CreateProperty(Container, LA_PROP_SUB, Identifier, Name, Description, 0, 0, DefaultWidget, Tag);
+
+    p->Base.Offset = OffsetSize;
+    p->Get = Get;
+    p->GetNext = GetNext;
+    p->GetActive = GetActive;
+    p->Set = Set;
+    p->GetState = GetState;
+    p->SetState = SetState;
+    p->TargetID = TargetId;
+    p->Base.OffsetIsPointer = (Tag & LA_UDF_LOCAL) ? 0 : 1;
+    p->Base.UiDefine = DefaultUiDef;
+    p->GetType = GetType;
+    p->ListHandleOffset = ListHandleOffset;
+    
+    p->Base.UDFNoCreate = (Tag & LA_UDF_LOCAL) ? 1 : 0;
+
+    if (Tag & LA_UDF_SINGLE || (p->Base.OffsetIsPointer && !p->ListHandleOffset && !p->GetNext && !(Tag & LA_UDF_REFER))) p->Base.UDFIsSingle = 1;
+
+    la_AssignPropertyGeneralSub(p);
+
+    return p;
+}
+
+void laSubGroupExtraFunctions(laProp* p, laSubUIFilterF* UiFilter, laSubUIThemeF* GetTheme, laSubUIGapF GetGap){
+    laSubProp *sp=p;
+    sp->UiFilter=UiFilter; sp->GetTheme=GetTheme; sp->GetGap=GetGap;
+}
+void laSubGroupDetachable(laProp *SubProp, laSubTypeDetachedGet DetachedGet, laSubTypeDetachedGetNext DetachedGetNext){
+    laSubProp *sp = SubProp;
+    SubProp->Tag |= LA_DETACHABLE;
+    sp->DetachedGet = DetachedGet;
+    sp->DetachedGetNext = DetachedGetNext;
+}
+
+laProp *laAddOperatorProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description,
+                              const char *OperatorID, uint32_t IconID, laWidget* DefaultWidget){
+
+    laOperatorProp *p = la_CreateProperty(Container, LA_PROP_OPERATOR, Identifier, Name, Description, 0, 0, DefaultWidget, 0);
+
+    p->OperatorID = OperatorID;
+    p->Base.IconID = IconID;
+
+    la_AssignPropertyGeneralSub(p);
+
+    return p;
+}
+
+laProp *laAddRawProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, int OffsetSize, laRawGetSizeF GetSize, laRawGetF RawGet, laRawSetF RawSet, u64bit Tag){
+    if(!RawGet && !GetSize) return 0;
+    laRawProp *p = la_CreateProperty(Container, LA_PROP_RAW, Identifier, Name, Description, 0, 0, 0, Tag);
+    p->Base.Offset = OffsetSize;
+    p->Base.OffsetIsPointer = (Tag & LA_UDF_LOCAL) ? 0 : 1;
+    p->RawGet=RawGet;
+    p->RawGetSize=GetSize;
+    p->RawSet=RawSet;
+    la_AssignPropertyGeneralSub(p);
+    return p;
+}
+
+
+//void laPropertySignal(laProp* p, int Throw, int Catch) {
+//	p->SignalThrow = Throw;
+//	p->SignalCatch = Catch;
+//}
+
+int laIsPropertyReadOnly(laPropPack *pp){
+    if (pp && pp->LastPs && pp->LastPs->p->ReadOnly) return 1;
+    return 0;
+}
+
+int laGetPrefixP(laPropPack *p, char buf[8][64]){
+    char *prefix = transLate(p->LastPs->p->Prefix);
+    int i = 0, row = 0;
+
+    if (!prefix) return 0;
+
+    int len=strlen(prefix);
+    while ((prefix[i] != L'\0') && (i+=1+strGetStringTerminateBy(&prefix[i], L',', &buf[row]))){
+        row++; if(i>=len){break;}
+    }
+
+    return 1;
+}
+int laGetPrefix(laProp *p, char buf[8][64]){
+    char *prefix = transLate(p->Prefix);
+    int i = 0, row = 0;
+
+    if (!prefix) return 0;
+
+    while ((prefix[i] != L'\0') && (i += 1 + strGetStringTerminateBy(&prefix[i], L',', &buf[row]))) row++;
+
+    return 1;
+}
+
+laPropContainer* laGetInstanceType(laPropPack* pp, void* instance){
+    if(pp->LastPs->p->PropertyType != LA_PROP_SUB) return 0;
+    laSubProp* sp = pp->LastPs->p;
+    if(instance && sp->GetType){ return sp->GetType(instance); }
+    return pp->LastPs->p->SubProp;
+}
+laUiDefineFunc* laGetPropertyUiDefine(laPropPack* pp, void* instance){
+    if(pp->LastPs->p->UiDefine) return pp->LastPs->p->UiDefine;
+    laPropContainer* pc=laGetInstanceType(pp, instance);
+    if(pc && pc->UiDefine) return pc->UiDefine;
+    return laui_SubPropInfoDefault;
+}
+
+laPropContainer* la_EnsureSubTarget(laSubProp* sp, void* optional_instance){
+    if(optional_instance&&sp->GetType) return sp->GetType(optional_instance);
+    if(sp->Base.SubProp){ return sp->Base.SubProp; }
+    if(sp->TargetID)sp->Base.SubProp=la_ContainerLookup(sp->TargetID); return sp->Base.SubProp;
+}
+
+int laReadInt(laPropPack *pp, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        laIntProp *p = pp->LastPs->p;
+        if (p->Read) p->Read(pp->LastPs->UseInstance, n);
+        else
+            laSetInt(pp, n);
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetInt(laPropPack *pp, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        laIntProp *p = pp->LastPs->p;
+        if (p->Max != p->Min){
+            n = n > p->Max ? p->Max : (n < p->Min ? p->Min : n);
+        }
+        if (p->Base.DetachedPP.LastPs){
+            p->Detached[0] = n;
+            laNotifyUsersPP(pp);
+            return;
+        }
+        if (p->Set) p->Set(pp->LastPs->UseInstance, n);
+        elif (pp->LastPs->p->Offset>=0){
+            if (!p->Base.ElementBytes || p->Base.ElementBytes == 4){
+                if (pp->LastPs->p->OffsetIsPointer) (**((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+                else (*((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            }elif (p->Base.ElementBytes == 2){
+                if (pp->LastPs->p->OffsetIsPointer) (**((short **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+                else (*((short *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            }elif (p->Base.ElementBytes == 1){
+                if (pp->LastPs->p->OffsetIsPointer) (**((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+                else (*((BYTE *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laGetInt(laPropPack *pp){
+    int n;
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        laIntProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            return p->Detached[0];
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (((laIntProp *)pp->LastPs->p)->Get) return ((laIntProp *)pp->LastPs->p)->Get(pp->LastPs->UseInstance);
+        elif (pp->LastPs->p->Offset>=0){
+            if (!p->Base.ElementBytes || p->Base.ElementBytes == 4){
+                if (pp->LastPs->p->OffsetIsPointer) n = (**((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+                else n = (*((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            }elif (p->Base.ElementBytes == 2){
+                if (pp->LastPs->p->OffsetIsPointer) n = (**((short **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+                else n = (*((short *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            }elif (p->Base.ElementBytes == 1){
+                if (pp->LastPs->p->OffsetIsPointer) n = (**((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+                else n = (*((BYTE *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            }
+            return n;
+        }
+    }
+    return 0;
+}
+int laReadFloat(laPropPack *pp, real n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        laFloatProp *p = pp->LastPs->p;
+        if (p->Read) p->Read(pp->LastPs->UseInstance, n);
+        else
+            laSetFloat(pp, n);
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetFloat(laPropPack *pp, real n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        laFloatProp *p = pp->LastPs->p;
+        if (p->Max != p->Min){
+            n = n > p->Max ? p->Max : (n < p->Min ? p->Min : n);
+        }
+        if (p->Base.DetachedPP.LastPs){
+            p->Detached[0] = n;
+            laNotifyUsersPP(pp);
+            return;
+        }
+        if (p->Set) p->Set(pp->LastPs->UseInstance, n);
+        elif (pp->LastPs->p->Offset>=0){
+            if (pp->LastPs->p->OffsetIsPointer) (**((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            else (*((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+real laGetFloat(laPropPack *pp){
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        laFloatProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            return p->Detached[0];
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (((laFloatProp *)pp->LastPs->p)->Get) return ((laFloatProp *)pp->LastPs->p)->Get(pp->LastPs->UseInstance);
+        elif (pp->LastPs->p->Offset>=0){
+            if (pp->LastPs->p->OffsetIsPointer) return (**((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            else return (*((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+        }
+    }
+    return 0;
+}
+int laGetArrayLength(laPropPack *pp){
+    if (!pp->LastPs->p) return 0;
+    if (pp->LastPs->p->GetLen) return pp->LastPs->p->GetLen(pp->LastPs->UseInstance);
+    else{
+        if(pp->LastPs->p->Len==0) pp->LastPs->p->Len=1;
+        return pp->LastPs->p->Len;
+    }
+}
+int laSetIntArraySingle(laPropPack *pp, int index, int n){
+    laIntProp *p = pp->LastPs->p;
+    if (p->Max != p->Min){
+        n = n > p->Max ? p->Max : (n < p->Min ? p->Min : n);
+    }
+    if (p->Base.DetachedPP.LastPs){
+        p->Detached[index] = n;
+        laNotifyUsersPP(pp);
+        return;
+    }
+    if (!pp->LastPs->UseInstance) return 0;
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        if (p->SetArr){
+            p->SetArr(pp->LastPs->UseInstance, index, n);
+            laNotifyUsersPP(pp);
+            return 1;
+        }elif(p->SetAllArr){
+            int len = laGetArrayLength(pp); int* t=malloc(len*sizeof(int));
+            laGetIntArray(pp, t); t[index]=n;
+            laSetIntArrayAllArray(pp, t); free(t);
+            return 1;
+        }elif(p->Set){
+            laSetInt(pp, n);
+            return 1;
+        }elif (pp->LastPs->p->Offset>=0){
+            int *src = (pp->LastPs->p->OffsetIsPointer) ? ((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            src[index] = n; laNotifyUsersPP(pp); return 1;
+        }
+    }
+    return 0;
+}
+int laSetIntArrayAll(laPropPack *pp, int n){
+    laIntProp *p = pp->LastPs->p;
+    if (p->Max != p->Min){
+        n = n > p->Max ? p->Max : (n < p->Min ? p->Min : n);
+    }
+    if (p->Base.DetachedPP.LastPs){
+        int i = 0, len = laGetArrayLength(pp);
+        for (i; i < len; i++){
+            p->Detached[i] = n;
+        }
+        laNotifyUsersPP(pp);
+        return;
+    }
+    if (!pp->LastPs->UseInstance) return 0;
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        if (p->SetAll) p->SetAll(pp->LastPs->UseInstance, n);
+        else if (p->SetArr){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                p->SetArr(pp->LastPs->UseInstance, i, n);
+            }
+        }elif (pp->LastPs->p->Offset>=0){
+            real *src = (pp->LastPs->p->OffsetIsPointer) ? ((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){ src[i] = n; }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laReadIntArrayAllArray(laPropPack *pp, int *arr){
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        if (((laIntProp *)pp->LastPs->p)->Base.DetachedPP.LastPs){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                ((laIntProp *)pp->LastPs->p)->Detached[i] = arr[i];
+            }
+            return;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (((laIntProp *)pp->LastPs->p)->SetAllArr) ((laIntProp *)pp->LastPs->p)->SetAllArr(pp->LastPs->UseInstance, arr);
+        else
+            laSetIntArrayAllArray(pp, arr);
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetIntArrayAllArray(laPropPack *pp, int *arr){
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        if (((laIntProp *)pp->LastPs->p)->Base.DetachedPP.LastPs){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                ((laIntProp *)pp->LastPs->p)->Detached[i] = arr[i];
+            }
+            laNotifyUsersPP(pp);
+            return 1;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (((laIntProp *)pp->LastPs->p)->SetAllArr) ((laIntProp *)pp->LastPs->p)->SetAllArr(pp->LastPs->UseInstance, arr);
+        else if (((laIntProp *)pp->LastPs->p)->SetArr){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                ((laIntProp *)pp->LastPs->p)->SetArr(pp->LastPs->UseInstance, i, arr[i]);
+            }
+        }else if (pp->LastPs->p->Offset>=0){
+            int *src = (pp->LastPs->p->OffsetIsPointer) ? ((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                src[i] = arr[i];
+            }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laGetIntArray(laPropPack *pp, int *result){
+    if (pp->LastPs->p->PropertyType & LA_PROP_INT){
+        laIntProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            int len = laGetArrayLength(pp);
+            memcpy(result, p->Detached, len * sizeof(int));
+            return 1;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (!((laIntProp *)pp->LastPs->p)->GetAll){
+            int len = laGetArrayLength(pp);
+            if(len==1){ *result=laGetInt(pp); return; }
+            if(pp->LastPs->p->Offset>=0){
+                int *src = (pp->LastPs->p->OffsetIsPointer) ? ((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+                memcpy(result, src, len * sizeof(int));
+            }else{ *result=0; }
+            return 1;
+        }else{
+            ((laIntProp *)pp->LastPs->p)->GetAll(pp->LastPs->UseInstance, result);
+            return 1;
+        }
+    }
+    return 0;
+}
+int laSetFloatArraySingle(laPropPack *pp, int index, real n){
+    laFloatProp *p = pp->LastPs->p;
+    //if (pp->LastPs->p->Tag&LA_COLOR_DATA) {
+    //	if (MAIN.ColorAccessCorrectGamma && index!=3) {
+    //		tnsSingleLogToLinear(&n, MAIN.Gamma);
+    //	}
+    //}
+    if (p->Max != p->Min){
+        n = n > p->Max ? p->Max : (n < p->Min ? p->Min : n);
+    }
+    if (p->Base.DetachedPP.LastPs){
+        p->Detached[index] = n;
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    if (!pp->LastPs->UseInstance) return 0;
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        if (p->SetArr){
+            p->SetArr(pp->LastPs->UseInstance, index, n);
+            laNotifyUsersPP(pp);
+            return 1;
+        }elif(p->SetAllArr){
+            int len = laGetArrayLength(pp); real* t=malloc(len*sizeof(real));
+            laGetFloatArray(pp, t); t[index]=n;
+            laSetFloatArrayAllArray(pp, t); free(t);
+            return 1;
+        }elif(p->Set){
+            laSetFloat(pp, n);
+            return 1;
+        }elif (pp->LastPs->p->Offset>=0){
+            real *src = (pp->LastPs->p->OffsetIsPointer) ? ((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            src[index] = n;
+            laNotifyUsersPP(pp);
+            return 1;
+        }
+    }
+    return 0;
+}
+int laSetFloatArrayAll(laPropPack *pp, real n){
+    laFloatProp *p = pp->LastPs->p;
+    //if (pp->LastPs->p->Tag&LA_COLOR_DATA) {
+    //	if (MAIN.ColorAccessCorrectGamma) {
+    //		tnsSingleLogToLinear(&n, MAIN.Gamma);
+    //	}
+    //}
+    if (p->Max != p->Min){
+        n = n > p->Max ? p->Max : (n < p->Min ? p->Min : n);
+    }
+    if (p->Base.DetachedPP.LastPs){
+        int i = 0, len = laGetArrayLength(pp);
+        for (i; i < len; i++){
+            p->Detached[i] = n;
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    if (!pp->LastPs->UseInstance) return 0;
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        if (p->SetAll) p->SetAll(pp->LastPs->UseInstance, n);
+        else if (p->SetArr){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                p->SetArr(pp->LastPs->UseInstance, i, n);
+            }
+        }else if (pp->LastPs->p->Offset>=0){
+            real *src = (pp->LastPs->p->OffsetIsPointer) ? ((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){ src[i] = n; }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laReadFloatArrayAllArray(laPropPack *pp, real *arr){
+    //if (pp->LastPs->p->Tag&LA_COLOR_DATA) {
+    //	if (MAIN.ColorAccessCorrectGamma) {
+    //		tnsLogToLinear(arr, MAIN.Gamma);
+    //	}
+    //}
+    if (((laFloatProp *)pp->LastPs->p)->Base.DetachedPP.LastPs){
+        int i = 0, len = laGetArrayLength(pp);
+        for (i; i < len; i++){
+            ((laFloatProp *)pp->LastPs->p)->Detached[i] = arr[i];
+        }
+        return 1;
+    }
+    if (!pp->LastPs->UseInstance) return 0;
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        if (((laFloatProp *)pp->LastPs->p)->ReadAll) ((laFloatProp *)pp->LastPs->p)->ReadAll(pp->LastPs->UseInstance, arr);
+        else if (((laFloatProp *)pp->LastPs->p)->SetArr){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                ((laFloatProp *)pp->LastPs->p)->SetArr(pp->LastPs->UseInstance, i, arr[i]);
+            }
+        }else if (pp->LastPs->p->Offset>=0){
+            real *src = (pp->LastPs->p->OffsetIsPointer) ? ((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){ src[i] = arr[i]; }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetFloatArrayAllArray(laPropPack *pp, real *arr){
+    //if (pp->LastPs->p->Tag&LA_COLOR_DATA) {
+    //	if (MAIN.ColorAccessCorrectGamma) {
+    //		tnsLogToLinear(arr, MAIN.Gamma);
+    //	}
+    //}
+    if (((laFloatProp *)pp->LastPs->p)->Base.DetachedPP.LastPs){
+        int i = 0, len = laGetArrayLength(pp);
+        for (i; i < len; i++){
+            ((laFloatProp *)pp->LastPs->p)->Detached[i] = arr[i];
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    if (!pp->LastPs->UseInstance) return 0;
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        if (((laFloatProp *)pp->LastPs->p)->SetAllArr) ((laFloatProp *)pp->LastPs->p)->SetAllArr(pp->LastPs->UseInstance, arr);
+        else if (((laFloatProp *)pp->LastPs->p)->SetArr){
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){
+                ((laFloatProp *)pp->LastPs->p)->SetArr(pp->LastPs->UseInstance, i, arr[i]);
+            }
+        }else if (pp->LastPs->p->Offset>=0){
+            real *src = (pp->LastPs->p->OffsetIsPointer) ? ((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            int i = 0, len = laGetArrayLength(pp);
+            for (i; i < len; i++){ src[i] = arr[i]; }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laGetFloatArray(laPropPack *pp, real *result){
+    if (pp->LastPs->p->PropertyType & LA_PROP_FLOAT){
+        laFloatProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            int len = laGetArrayLength(pp);
+            memcpy(result, p->Detached, len * sizeof(real));
+            return;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (!((laFloatProp *)pp->LastPs->p)->GetAll){
+            int len = laGetArrayLength(pp);
+            if(len==1){ *result=laGetFloat(pp); return; }
+            if(pp->LastPs->p->Offset>=0){
+                real *src = (pp->LastPs->p->OffsetIsPointer) ? ((real **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) : ((real *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+                memcpy(result, src, len * sizeof(real));
+            }else{ *result=0; }
+            return 1;
+            //if (pp->LastPs->p->Tag&LA_COLOR_DATA) {
+            //	if (MAIN.ColorAccessCorrectGamma) {
+            //		tnsLinearToLog(result,MAIN.Gamma);
+            //	}
+            //}
+        }else{
+            ((laFloatProp *)pp->LastPs->p)->GetAll(pp->LastPs->UseInstance, result);
+            //if (pp->LastPs->p->Tag&LA_COLOR_DATA) {
+            //	if (MAIN.ColorAccessCorrectGamma) {
+            //		tnsLinearToLog(result, MAIN.Gamma);
+            //	}
+            //}
+            return 1;
+        }
+    }
+    return 0;
+}
+int laReadEnum(laPropPack *pp, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        if (((laEnumProp *)pp->LastPs->p)->Read) ((laEnumProp *)pp->LastPs->p)->Read(pp->LastPs->UseInstance, n);
+        else laSetEnum(pp, n);
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetEnumExternal(laPropPack *pp, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        laEnumProp *ep = pp->LastPs->p;
+        laEnumItem *ei;
+        int i = 0;
+        for (ei = ep->Items.pFirst; ei; ei = ei->Item.pNext){
+            if (i == n) break; i++;
+        }
+        laSetEnum(pp, ei->Index);
+    }
+    return 0;
+}
+int laSetEnum(laPropPack *pp, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        laEnumProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            p->Detached[0] = n;
+            laNotifyUsersPP(pp);
+            return 1;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (p->Set) p->Set(pp->LastPs->UseInstance, n);
+        elif(p->Base.Offset>=0) {
+            if (!p->Base.ElementBytes || p->Base.ElementBytes == 4){
+                if (pp->LastPs->p->OffsetIsPointer) (**((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+                else (*((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            }elif (p->Base.ElementBytes == 2){
+                if (pp->LastPs->p->OffsetIsPointer) (**((short **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+                else (*((short *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            }elif (p->Base.ElementBytes == 1){
+                if (pp->LastPs->p->OffsetIsPointer) (**((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+                else (*((BYTE *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset))) = n;
+            }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laReadEnumArrayAll(laPropPack *pp, int *n){
+    int i, len = pp->LastPs->p->Len;
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        if (((laEnumProp *)pp->LastPs->p)->ReadAll) ((laEnumProp *)pp->LastPs->p)->ReadAll(pp->LastPs->UseInstance, n);
+        else
+            for (i = 0; i < len; i++){
+                laSetEnumArrayIndexed(pp, i, n[i]);
+            }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetEnumArrayIndexedExternal(laPropPack *pp, int index, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        laEnumProp *ep = pp->LastPs->p;
+        laEnumItem *ei;
+        int i = 0;
+        for (ei = ep->Items.pFirst; ei; ei = ei->Item.pNext){
+            if (i == n) break;
+            i++;
+        }
+        laSetEnumArrayIndexed(pp, index,ei->Index);
+    }
+    return 0;
+}
+int laSetEnumArrayIndexed(laPropPack *pp, int index, int n){
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        laEnumProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            p->Detached[index] = n; 
+            laNotifyUsersPP(pp);return 1;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+        if (p->SetArr) p->SetArr(pp->LastPs->UseInstance, index, n);
+        elif(p->Set && index==0){ laSetEnum(pp, n); } 
+        elif(p->Base.Offset>=0){
+            if (!p->Base.ElementBytes || p->Base.ElementBytes == 4){
+                if (pp->LastPs->p->OffsetIsPointer) (**((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + sizeof(int) * index))) = n;
+                else (*((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + sizeof(int) * index))) = n;
+            }elif (p->Base.ElementBytes == 2){
+                if (pp->LastPs->p->OffsetIsPointer) (**((short **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + sizeof(short) * index))) = n;
+                else (*((short *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + sizeof(short) * index))) = n;
+            }elif (p->Base.ElementBytes == 1){
+                if (pp->LastPs->p->OffsetIsPointer) (**((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + sizeof(char) * index))) = n;
+                else (*((BYTE *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + sizeof(char) * index))) = n;
+            }
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetEnumArrayAllArray(laPropPack* pp, laEnumItem** ei){
+    int len=laGetArrayLength(pp);
+    for(int i=0;i<len;i++){
+        laSetEnumArrayIndexed(pp,i,ei[i]->Index);
+    }
+	return 0;
+}
+int laSetEnumArrayAll(laPropPack* pp, int EnumN){
+    int len=laGetArrayLength(pp);
+    laEnumProp *ep = pp->LastPs->p; laEnumItem *ei;
+    int i = 0; for (ei = ep->Items.pFirst; ei; ei = ei->Item.pNext){ if (i == EnumN) break; i++; }
+    for(int i=0;i<len;i++){
+        laSetEnumArrayIndexed(pp,i,ei->Index);
+    }
+	return 0;
+}
+laEnumItem *laGetEnum(laPropPack *pp){
+    int n;
+    laEnumItem *ei;
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        laEnumProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            n = p->Detached[0];
+        }elif (!pp->LastPs->UseInstance) return 0;
+        elif (p->Get) n = p->Get(pp->LastPs->UseInstance);
+        elif(p->Base.Offset>=0){
+            if (!pp->LastPs->UseInstance) n = 0;
+            elif (!p->Base.ElementBytes || p->Base.ElementBytes == 4){
+                if (pp->LastPs->p->OffsetIsPointer) n = (**((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+                else n = (*((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            }elif (p->Base.ElementBytes == 2){
+                if (pp->LastPs->p->OffsetIsPointer) n = (**((short **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+                else n = (*((short *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            }elif (p->Base.ElementBytes == 1){
+                if (pp->LastPs->p->OffsetIsPointer) n = (**((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+                else n = (*((BYTE *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)));
+            }
+        }
+        for (ei = p->Items.pFirst; ei; ei = ei->Item.pNext){
+            if (n == ei->Index) return ei;
+        }
+    }
+    return ((laEnumProp *)pp->LastPs->p)->Items.pFirst;
+}
+laEnumItem *laGetEnumArrayIndexed(laPropPack *pp, int index){
+    int n;
+    int i = 0;
+    laEnumItem *ei;
+    int result[16];
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        laEnumProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            n = p->Detached[index];
+        }elif (!p->GetAll){
+            if(laGetArrayLength(pp)==1){return laGetEnum(pp);}
+            if(p->Base.Offset>=0){
+                if (!pp->LastPs->UseInstance) n = 0;
+                elif (!p->Base.ElementBytes || p->Base.ElementBytes == 4){
+                    if (pp->LastPs->p->OffsetIsPointer) n = (**((int **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) + index * sizeof(int));
+                    else n = (*((int *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + index * sizeof(int))));
+                }elif (p->Base.ElementBytes == 2){
+                    if (pp->LastPs->p->OffsetIsPointer) n = (**((short **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) + index * sizeof(short));
+                    else n = (*((short *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + index * sizeof(short))));
+                }elif (p->Base.ElementBytes == 1){
+                    if (pp->LastPs->p->OffsetIsPointer) n = (**((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset)) + index * sizeof(char));
+                    else n = (*((BYTE *)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset + index * sizeof(char))));
+                }
+            }
+        }else{
+            if (!pp->LastPs->UseInstance) n = 0;
+            else{
+                p->GetAll(pp->LastPs->UseInstance, result);
+                n = result[index];
+            }
+        }
+        for (ei = p->Items.pFirst; ei; ei = ei->Item.pNext){
+            if (n == ei->Index) return ei;
+        }
+    }
+    return 0;
+}
+int laGetEnumArray(laPropPack *pp, laEnumItem **result){
+    int len = laGetArrayLength(pp);
+    int i = 0;
+    laEnumItem *ei;
+    int Results[16];
+
+    laEnumProp *p = pp->LastPs->p;
+    if (p->Base.DetachedPP.LastPs){
+        for (int i = 0; i < len; i++){
+            Results[i] = p->Detached[i];
+            for (ei = ((laEnumProp *)pp->LastPs->p)->Items.pFirst; ei; ei = ei->Item.pNext){
+                if (ei->Index == Results[i]){result[i] = ei; break;}
+            }
+        }
+    }elif (!((laEnumProp *)pp->LastPs->p)->GetAll){
+        for (i; i < len; i++){
+            result[i] = laGetEnumArrayIndexed(pp, i);
+        }
+        return 1;
+    }else{
+        int a = 0;
+        ((laEnumProp *)pp->LastPs->p)->GetAll(pp->LastPs->UseInstance, Results);
+        for (i = 0; i < len; i++){
+            for (ei = ((laEnumProp *)pp->LastPs->p)->Items.pFirst; ei; ei = ei->Item.pNext){
+                if (ei->Index == Results[i]){ result[i] = ei; break; }
+            }
+        }
+    }
+}
+laEnumItem *laGetEnumFromIdentifier(laEnumProp *p, char *Identifier){
+    laEnumItem *ei;
+    for (ei = p->Items.pFirst; ei; ei = ei->Item.pNext){
+        if (!strcmp(ei->Identifier, Identifier)) return ei;
+    }
+    return 0;
+}
+int laEnumHasIcon(laPropPack *pp){
+    laEnumProp *p = pp->LastPs->p;
+    laEnumItem *ei;
+    if ((p->Base.PropertyType & LA_PROP_ENUM) != LA_PROP_ENUM) return 0;
+    for (ei = p->Items.pFirst; ei; ei = ei->Item.pNext){
+        if (ei->IconID) return 1;
+    }
+    return 0;
+}
+laEnumItem *laGetEnumEntryLen(laPropPack *pp){
+    int i = 0;
+    laEnumItem *ei;
+    if (pp->LastPs->p->PropertyType & LA_PROP_ENUM){
+        if (((laEnumProp *)pp->LastPs->p)->GetLen) return ((laEnumProp *)pp->LastPs->p)->GetLen(pp->LastPs->UseInstance);
+        for (ei = ((laEnumProp *)pp->LastPs->p)->Items.pFirst; ei; ei = ei->Item.pNext){
+            i += 1;
+        }
+        return i;
+    }
+    return 0;
+}
+int laReadString(laPropPack *pp, char *str){
+    if (pp->LastPs->p->PropertyType == LA_PROP_STRING){
+        if (((laStringProp *)pp->LastPs->p)->Read) ((laStringProp *)pp->LastPs->p)->Read(pp->LastPs->UseInstance, str);
+        else
+            laSetString(pp, str);
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laSetString(laPropPack *pp, char *str){
+    char **add = 0;
+    if (pp->LastPs->p->PropertyType == LA_PROP_STRING){
+        laStringProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            strCopyFull(p->Detached, str);
+            laNotifyUsersPP(pp);
+            return 1;
+        }
+
+        if (p->Set){
+            p->Set(pp->LastPs->UseInstance, str);
+            laNotifyUsersPP(pp);
+            return 1;
+        }
+
+        if (!pp->LastPs->UseInstance) return 0;
+
+        if (p->IsSafeString){
+            add = ((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+            strSafeSet(add, str);
+            laNotifyUsersPP(pp);
+            return 1;
+        }
+        if (p->Base.Offset){
+            if (p->Base.OffsetIsPointer){
+                add = ((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+                if (!(*add)) return 0;
+                strCopyFull(*add, str);
+            }else strCopyFull(((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset), str);
+        }
+        laNotifyUsersPP(pp);
+        return 1;
+    }
+    return 0;
+}
+int laGetString(laPropPack *pp, char *result, char** direct_result){
+    if (pp->LastPs->p->PropertyType == LA_PROP_STRING){
+        laStringProp *p = pp->LastPs->p;
+        if (p->Base.DetachedPP.LastPs){
+            strCopyFull(result, p->Detached);
+            return 1;
+        }
+        if (!pp->LastPs->UseInstance) return 0;
+
+        if (p->Get){ p->Get(pp->LastPs->UseInstance, result, direct_result); return 1; }
+
+        if (pp->LastPs->p->Offset>=0){
+            if (p->IsSafeString){
+                laSafeString **add = ((laSafeString **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+                if (!*add) return 0;
+                if((*add)->Ptr){ *direct_result = (*add)->Ptr; return 1;}
+                return 0;
+            }else{
+                if (pp->LastPs->p->OffsetIsPointer) *direct_result=*((char **)((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset));
+                else  *direct_result=((BYTE *)pp->LastPs->UseInstance + pp->LastPs->p->Offset);
+            }
+        }
+        return 1;
+    }
+    return 0;
+}
+void *laGetInstance(laProp *sub, void *FromInstance, laPropIterator *Iter){
+    laSubProp *sp = sub;
+    laPropIterator IT = {0};
+    if (!Iter) Iter = &IT;
+    if (Iter) Iter->Parent = FromInstance;
+    if (sub->PropertyType == LA_PROP_SUB){
+        if (sp->Base.DetachedPP.LastPs){ if(sp->DetachedGet) return sp->DetachedGet(0, Iter);
+            return sp->Detached;
+        }
+        if (!FromInstance) return 0;
+        if (sp->Get) return sp->Get(FromInstance, Iter);
+        else if (sp->ListHandleOffset){
+            void *address = *((long long *)((BYTE *)FromInstance + sp->ListHandleOffset));
+            return address;
+        }else return laGetActiveInstance(sub, FromInstance, Iter);
+    }
+    return 0;
+}
+void *laGetNextInstance(laProp *sub, void *ThisInstance, laPropIterator *Iter){
+    laSubProp *sp = sub;
+    if (sub->PropertyType == LA_PROP_SUB){
+        if (sp->Base.DetachedPP.LastPs && sp->DetachedGetNext) return sp->DetachedGetNext(ThisInstance, Iter);
+        if (!ThisInstance) return 0;
+        if (sp->GetNext) return (sp->GetNext(ThisInstance, Iter));
+        else if (sp->ListHandleOffset){
+            laListItem *li = ThisInstance;
+            return li->pNext;
+        }
+    }
+    return 0;
+}
+void *laGetActiveInstanceStrict(laProp *sub, void *FromInstance){
+    laSubProp *sp = sub;
+    if (sub->PropertyType == LA_PROP_SUB){
+        if (sp->Base.DetachedPP.LastPs){
+            return sp->Detached;
+        }
+        if (!FromInstance) return 0;
+        if (sp->GetActive) return sp->GetActive(FromInstance, 0);
+        if (sub->Offset>=0){
+            if (sub->OffsetIsPointer /*&& (sp->Get||sp->ListHandleOffset)*/){
+                void **a = (void **)((BYTE *)FromInstance + sub->Offset); return *a;
+            }else return ((BYTE *)FromInstance + sub->Offset);
+        }
+    }
+    return 0; // laGetInstance(sub, FromInstance, 0);
+}
+void *laGetActiveInstance(laProp *sub, void *FromInstance, laPropIterator *Iter){
+    laSubProp *sp = sub;
+    if (sub->PropertyType == LA_PROP_SUB){
+        if (sp->Base.DetachedPP.LastPs){
+            return sp->Detached;
+        }
+        if (!FromInstance) return 0;
+        if (sp->GetActive) return sp->GetActive(FromInstance, Iter);
+        if (sp->Get) return laGetInstance(sub, FromInstance, Iter);
+        if (sub->Offset>=0){
+            if (sub->OffsetIsPointer){
+                void **a = (void **)((BYTE *)FromInstance + sub->Offset); return *a;
+            }else return ((BYTE *)FromInstance + sub->Offset);
+        }
+    }
+    return 0;
+}
+void laSetActiveInstance(laProp *sub, void *FromInstance, void *Instance){
+    laSubProp *sp = sub;
+    if (sub->PropertyType == LA_PROP_SUB){
+        if (sp->Base.DetachedPP.LastPs){
+            sp->Detached = Instance;
+            laNotifySubPropUsers(sp, FromInstance);
+            return;
+        }
+        if (!FromInstance) return 0;
+        if (sp->SetState){
+            laNotifySubPropUsers(sp, FromInstance);
+            return sp->SetState(FromInstance, Instance, LA_UI_ACTIVE);
+        }
+        if (sp->Set){
+            laNotifySubPropUsers(sp, FromInstance);
+            return sp->Set(FromInstance, Instance);
+        }
+        if (sub->OffsetIsPointer && sub->Offset>=0){
+            void **a = (void **)((BYTE *)FromInstance + sub->Offset);
+            memAssignRefSafe(sub->Container->Hyper?sp:0,FromInstance, a, Instance);
+            laNotifySubPropUsers(sp, FromInstance);
+        }
+    }
+    return;
+}
+void laAppendInstance(laSubProp *sub, void *FromInstance, void *Instance){
+    if (sub->ListHandleOffset){
+        lstAppendItem((BYTE *)FromInstance + sub->ListHandleOffset, Instance);
+    }
+}
+void* laGetRaw(laPropPack *pp, int* r_size, int* return_is_a_copy){
+    if (pp->LastPs->p->PropertyType == LA_PROP_RAW){
+        laRawProp* rp=pp->LastPs->p; 
+        if(rp->RawGet){ return rp->RawGet(pp->LastPs->UseInstance, r_size, return_is_a_copy); }
+        int s=rp->RawGetSize(pp->LastPs->UseInstance); void* data=0;
+        if(rp->Base.OffsetIsPointer){ data=*((void**)(((char*)pp->LastPs->UseInstance)+rp->Base.Offset)); }
+        else{ data=((char*)pp->LastPs->UseInstance)+rp->Base.Offset; }
+        *return_is_a_copy=0; if(r_size) *r_size=s;
+        return data;
+    } return 0;
+}
+int laSetRaw(laPropPack *pp, void* data, int _size){
+    if (pp->LastPs->p->PropertyType == LA_PROP_RAW){ laRawProp* rp=pp->LastPs->p;
+        if(rp->RawSet){ rp->RawSet(pp->LastPs->UseInstance, data, _size); return; }
+        if(rp->Base.OffsetIsPointer){ void** target=(((char*)pp->LastPs->UseInstance)+rp->Base.Offset); if(*target) free(*target);
+            void* newd=_size?calloc(1,_size):0; if(_size)memcpy(newd, data, _size); (*target)=newd;
+        }
+        else{ memcpy(((char*)pp->LastPs->UseInstance)+rp->Base.Offset,data,_size); }
+        return 1;
+    } return 0;
+}
+
+int laGetIntRange(laPropPack *pp, int *min, int *max){
+    laIntProp *p = pp->LastPs->p;
+    if (p->Max != p->Min){
+        *min = p->Min;
+        *max = p->Max;
+        return 1;
+    }
+    return 0;
+}
+int laGetFloatRange(laPropPack *pp, real *min, real *max){
+    laFloatProp *p = pp->LastPs->p;
+    if (p->Max != p->Min){
+        *min = p->Min;
+        *max = p->Max;
+        return 1;
+    }
+    return 0;
+}
+
+int laCanGetState(laProp *sub){ laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetState) return 1; } return 0; }
+int laCanGetTheme(laProp *sub){ laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetTheme) return 1; } return 0; }
+int laCanGetGap(laProp *sub){ laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetGap) return 1; } return 0; }
+int laGetUiState(laProp *sub, void *Instance){
+    laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetState) return sp->GetState(Instance); } return 0;
+}
+laBoxedTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance){
+    laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetTheme) return sp->GetTheme(parent,Instance); } return 0;
+}
+int laGetUiGap(laProp *sub, void* parent, void *Instance){
+    laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetGap) return sp->GetGap(parent,Instance); } return 0;
+}
+int laSetState(laProp *sub, void *FromInstance, void *Instance, int State){
+    laSubProp *sp = sub;
+    if (sub->PropertyType == LA_PROP_SUB){
+        if (sp->SetState){
+            laNotifySubPropUsers(sub, FromInstance);
+            return sp->SetState(FromInstance, Instance, State);
+        }
+    }
+    return 0;
+}
+int laActuateProp(laPropPack *This, laPropPack *RunPP, laOperator *OptionalFrom, laEvent *e){
+    if (RunPP->LastPs->p->PropertyType & LA_PROP_OPERATOR){
+        if (!((laOperatorProp *)RunPP->LastPs->p)->OperatorType){
+            ((laOperatorProp *)RunPP->LastPs->p)->OperatorType = laGetOperatorType(((laOperatorProp *)RunPP->LastPs->p)->OperatorID);
+        }
+        return laInvokeP(OptionalFrom, ((laOperatorProp *)RunPP->LastPs->p)->OperatorType, e, This, 0, 0); //ARGS
+    }
+}
+
+void laMarkPropChanged(laPropPack* pp){
+    if(!pp) return;
+    if(!pp->Go){ if(pp->LastPs&&pp->LastPs->p->Container && pp->LastPs->p->Container->Hyper==2 && pp->LastPs->UseInstance){ 
+            laMemNodeHyper* m=memGetHead(pp->LastPs->UseInstance,0); m->Modified=1; } }
+    else for(laPropStep* ps=pp->Go;ps;ps=ps->pNext){
+        if(ps->Type=='.' && ps->p->Container->Hyper==2 && ps->UseInstance){ 
+            laMemNodeHyper* m=memGetHead(ps->UseInstance,0); m->Modified=1; }
+    }
+    laMarkPropChanged(pp->RawThis);
+}
+
+laPropContainer *la_SetGeneralRoot(laPropContainer **GeneralRoot, const char *Identifier, const char *Name, const char *Description){
+    laPropContainer* ret =memAcquire(sizeof(laPropContainer));
+    *GeneralRoot = ret;
+    ret->Identifier = Identifier;
+    ret->Name = Name;
+    ret->Description = Description;
+    ret->OtherAlloc=1;
+    lstAppendItem(&MAIN.PropContainers, ret);
+    return ret;
+}
+
+void laSetRootInstance(void *root){
+    MAIN.DataRoot.RootInstance = root;
+}
+
+laPropContainer *laDefineRoot(){
+    if (!MAIN.DataRoot.Root) MAIN.DataRoot.Root = laAddPropertyContainer("root", "__ROOT__", "Root Node In NUL4.0 Data System", L'🞈', 0, 0, 0, 0, 2|LA_PROP_OTHER_ALLOC);
+    return MAIN.DataRoot.Root;
+}
+
+void laThrowToTrashBin(void *Data, char *ContainerString){
+    laPropContainer *pc = la_ContainerLookup(ContainerString);
+    lstAppendItem(&pc->TrashBin, Data);
+}
+
+int laValidateHyper2(laPropContainer* pc, laPropContainer* ParentHyper2, laSafeString** errors){
+    int pass=1;
+    for(laProp* p=pc->Props.pFirst;p;p=p->Item.pNext){
+        if(p->PropertyType!=LA_PROP_SUB) continue;
+        laSubProp* sp=p;
+        if(!p->SubProp && !sp->GetType){ 
+            p->SubProp=la_ContainerLookup(sp->TargetID);
+            if(!p->SubProp){
+                strSafePrint(errors, "Unable to locate property container \"%s\".\n", sp->TargetID); pass=0; continue; }
+            laPropContainer* spc=p->SubProp;
+            laPropContainer* sNoHyper2 = ParentHyper2;
+            if(!ParentHyper2){
+                if(pc->Hyper==2 && (!(p->UDFNoCreate||p->UDFIsRefer||p->UDFIsSingle))){ 
+                    sNoHyper2=pc; }
+            }
+            if(sNoHyper2){
+                if(spc->Hyper==2 && !sp->Base.UDFIsRefer){ strSafePrint(errors,\
+                    "Hyper2 list (\"%s\") under another Hyper2 container (\"%s\") is not allowed.\n",
+                    sp->TargetID, sNoHyper2->Identifier); pass=0; }
+            }
+            if(!laValidateHyper2(p->SubProp, sNoHyper2, errors)){pass=0;}
+            if(ParentHyper2) ParentHyper2->validated=1;
+        }
+    }
+    return pass;
+}
+int laValidateProperties(){
+    laSafeString* errors=0; int pass=1;
+    for(laPropContainer* pc=MAIN.PropContainers.pFirst;pc;pc=pc->Item.pNext){
+        if(pc->validated){continue;}
+        if(!laValidateHyper2(pc, 0, &errors)){ pass=0; }
+        pc->validated=1;
+    }
+    if(!pass){
+        printf("laValidateHyper2 Failed:\n"); printf(errors->Ptr);
+    }
+    return pass;
+}
+
+//==================================[RW]
+
+void la_GetWorkingDirectoryInternal(){
+    char mbuf[2048];
+    getcwd(mbuf,2048);
+    strSafeSet(&MAIN.WorkingDirectory, mbuf);
+}
+
+int laGetRelativeDirectory(char *FullFrom, char *FullTo, char *Result){
+    return 0;
+    //WIN32_FIND_DATA fd;
+    //HANDLE h;
+    //char *PathFrom = 0, *PathTo = 0;
+    //char FullFromP[1024], FullToP[1024]={0};
+    //char *FileNameOnly = 0;
+    //int seg, i;
+//
+    //Result[0] = 0;
+//
+    //if (!FullFrom || !FullTo || FullFrom[0] != FullTo[0])
+    //    return 0;
+//
+    //strcpy(FullFromP, FullFrom);
+    //strcpy(FullToP, FullTo);
+//
+    //while (h = FindFirstFile(FullFromP, &fd))
+    //{
+    //    if (h == INVALID_HANDLE_VALUE || (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
+    //    {
+    //        strDiscardLastSegmentSeperateBy(FullFromP, '/');
+    //        continue;
+    //    }
+    //    break;
+    //}
+//
+    //while (h = FindFirstFile(FullToP, &fd))
+    //{
+    //    if (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+    //    {
+    //        FileNameOnly = strGetLastSegment(FullToP, '/');
+    //        strDiscardLastSegmentSeperateBy(FullToP, '/');
+    //        continue;
+    //    }
+    //    elif (h == INVALID_HANDLE_VALUE)
+    //    {
+    //        strDiscardLastSegmentSeperateBy(FullToP, '/');
+    //        continue;
+    //    }
+    //    break;
+    //}
+//
+    //strDiscardSameBeginningSeperatedBy(FullFromP, FullToP, &PathFrom, &PathTo, '/');
+//
+    //seg = strCountSegmentSeperateBy(PathFrom, '/');
+//
+    //for (i = 0; i < seg; i++)
+    //{
+    //    strcat(Result, "../");
+    //}
+//
+    //strcat(Result, PathTo);
+//
+    //if (FileNameOnly)
+    //{
+    //    strcat(Result, "/");
+    //    strcat(Result, FileNameOnly);
+    //}
+//
+    //return 1;
+}
+void laGetUDFRelativeDirectory(laUDF *From, laUDF *To, char *Result){
+    if (!From || !To) return;
+    laGetRelativeDirectory(From->FileName->Ptr, To->FileName->Ptr, Result);
+}
+void laGetFullPath(char *FullFrom, char *Relative, char *Result){
+    //WIN32_FIND_DATA fd;
+    //HANDLE h;
+    //char *PathFrom = 0, *PathTo = 0;
+    //char FullFromP[1024] = {0};
+    //int seg, i;
+//
+    //Result[0] = 0;
+//
+    //if (!FullFrom)
+    //    return 0;
+//
+    //strcpy(FullFromP, FullFrom);
+//
+    //while (h = FindFirstFile(FullFromP, &fd))
+    //{
+    //    if (h == INVALID_HANDLE_VALUE || (!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)))
+    //    {
+    //        strDiscardLastSegmentSeperateBy(FullFromP, '/');
+    //        continue;
+    //    }
+    //    break;
+    //}
+    //strcpy(Result, FullFromP);
+    ////strcat(Result, "/");
+    //strcat(Result, Relative);
+}
+
+laUDF *laPrepareUDF(char *FileName){
+    laUDF *udf = memAcquire(sizeof(laUDF));
+    strSafeSet(&udf->FileName, FileName);
+    return udf;
+}
+
+int laWriteProp(laUDF *udf, char *Path){
+    laUDFPropSegment *ps = CreateNew(laUDFPropSegment);
+    strSafeSet(&ps->Path, Path);
+    la_GetPropFromPath(&ps->PP, 0, Path, 0);
+    la_StepPropPack(&ps->PP);
+    lstAppendItem(&udf->PropsToOperate, ps);
+    udf->NumSegmets++;
+}
+int laWritePropP(laUDF *udf, laPropPack *pp){
+    char buf[LA_RAW_CSTR_MAX_LEN] = {0};
+    laUDFPropSegment *ps = CreateNew(laUDFPropSegment);
+
+    ps->PPP = pp;
+    udf->NumSegmets++;
+
+    //la_GetPropPackFullPath(pp, Buf);
+    //strSafeSet(&ps->Path, Buf);
+
+    lstAppendItem(&udf->PropsToOperate, ps);
+}
+int la_IncludeHyper2Instance(laUDF *udf, laPropContainer* pc, void* Instance){
+    laUDFH2Instance *h2 = memAcquire(sizeof(laUDFH2Instance));
+    h2->pc=pc; h2->Instance = Instance;
+    lstAppendItem(&udf->H2Instances, h2);
+    udf->HasInstances=1;
+}
+int la_ClearHyper2Instances(laUDF* udf){
+    laUDFH2Instance *h2;
+    while(h2=lstPopItem(&udf->H2Instances)){ memFree(h2); }
+    udf->HasInstances=0;
+}
+
+//void la_UDFAppendPointerRecord(void* UseInstance, laSubProp* p, void** PendingReference,void* ReadInstance) {
+//	//laUDFPointerRecord* upr = &MAIN.PendingPointers[MAIN.NextPendingPointer];
+//	//if (!ReadInstance) return;
+//	//upr->ReadInstance = ReadInstance;
+//	//upr->PendingReference = PendingReference;
+//	//upr->SubProp = p;
+//	//upr->UseInstance = UseInstance;
+//	//MAIN.NextPendingPointer++;
+//}
+//void la_UDFAppendNUIDRecord(void* UseInstance, laSubProp* p, void** PendingReference, char * ReadNUID) {
+//	//laUDFPointerRecord* upr = &MAIN.PendingPointers[MAIN.NextPendingPointer];
+//	//if (!ReadNUID) return;
+//	//upr->NUID = CreateNewBuffer(char, 23);
+//	//strcpy(upr->NUID, ReadNUID);
+//	//upr->PendingReference = PendingReference;
+//	//upr->SubProp = p;
+//	//upr->UseInstance = UseInstance;
+//	//MAIN.NextPendingPointer++;
+//}
+//void la_UDFAppendPointerSync(void* ReadInstance, void* ActualInstance) {
+//	//laUDFPointerSync* ups = CreateNew(laUDFPointerSync);
+//	//ups->ReadPointer = ReadInstance;
+//	//ups->ActualPointer = ActualInstance;
+//	//hsh65536InsertItem(&MAIN.PointerSync, ups, ReadInstance);
+//}
+//void la_UDFAppendNUIDSync(char * ReadNUID, void* ActualInstance) {
+//	//laUDFPointerSync* ups = CreateNew(laUDFPointerSync);
+//	//ups->NUID = CreateNewBuffer(char, 23);
+//	//memcpy(ups->NUID, ReadNUID,sizeof(char)*23);
+//	//ups->ActualPointer = ActualInstance;
+//	//hsh65536InsertItem(&MAIN.PointerSync, ups, (long)ReadNUID[15]);
+//}
+
+void la_UDFAppendSharedTypePointer(char *ID, void *Pointer){
+    laSharedTypeItem *sti = memAcquireSimple(sizeof(laSharedTypeItem));
+    strCopyFull(sti->ID, ID);
+    sti->Pointer = Pointer;
+    lstAppendItem(&MAIN.SharedTypePointerSync, sti);
+}
+
+#define la_UseUDF(udf) udf->Used = 1
+
+u64bit la_Tell(laUDF *udf){
+    if (udf->DiskFile)
+        return ftell(udf->DiskFile);
+    else
+        return udf->Seek;
+}
+int la_Seek(laUDF *udf, u64bit Offset){
+    if (udf->DiskFile)
+        return fseek(udf->DiskFile, Offset, SEEK_SET);
+    udf->Seek = Offset;
+    return 1;
+}
+void la_WriteString(laUDF *udf, char *String){
+    short size = strlen(String);
+    fwrite(&size, sizeof(short), 1, udf->DiskFile);
+    if (size) fwrite(String, size*sizeof(char), 1, udf->DiskFile);
+}
+void la_WriteOnlyString(laUDF *udf, char *String){
+    fwrite(String, strlen(String), 1, udf->DiskFile);
+}
+void la_WriteOnlyMBString(laUDF *udf, char *String){
+    fwrite(String, strlen(String), 1, udf->DiskFile);
+}
+void la_WriteInt(laUDF *udf, int Data){
+    fwrite(&Data, sizeof(int), 1, udf->DiskFile);
+}
+void la_WriteUByte(laUDF *udf, unsigned char Data){
+    fwrite(&Data, sizeof(unsigned char), 1, udf->DiskFile);
+}
+void la_WriteShort(laUDF *udf, short Data){
+    fwrite(&Data, sizeof(short), 1, udf->DiskFile);
+}
+void la_WriteLong(laUDF *udf, long Data){
+    fwrite(&Data, sizeof(long), 1, udf->DiskFile);
+}
+void la_WritePointer(laUDF *udf, void *Data){
+    fwrite(&Data, sizeof(void *), 1, udf->DiskFile);
+}
+void la_WriteFloat(laUDF *udf, real Data){
+    fwrite(&Data, sizeof(real), 1, udf->DiskFile);
+}
+void la_WriteSized(laUDF *udf, void* Data, int size){
+    fwrite(Data, size, 1, udf->DiskFile);
+}
+short la_ReadShort(laUDF *udf){
+    short result;
+    if(!udf->FileContent){ fread(&result, sizeof(short), 1, udf->DiskFile); }
+    else{ memcpy(&result, udf->FileContent + udf->Seek, sizeof(short)); udf->Seek += sizeof(short); }
+    return result;
+}
+u8bit la_ReadUByte(laUDF *udf){
+    u8bit result;
+    if(!udf->FileContent){ fread(&result, sizeof(u8bit), 1, udf->DiskFile); }
+    else{ memcpy(&result, udf->FileContent + udf->Seek, sizeof(u8bit)); udf->Seek += sizeof(u8bit); }
+    return result;
+}
+int la_ReadInt(laUDF *udf){
+    int result;
+    if(!udf->FileContent){ fread(&result, sizeof(int), 1, udf->DiskFile); }
+    else{ memcpy(&result, udf->FileContent + udf->Seek, sizeof(int)); udf->Seek += sizeof(int); }
+    return result;
+}
+long la_ReadLong(laUDF *udf){
+    long result;
+    if(!udf->FileContent){ fread(&result, sizeof(long), 1, udf->DiskFile); }
+    else{ memcpy(&result, udf->FileContent + udf->Seek, sizeof(long)); udf->Seek += sizeof(long); }
+    return result;
+}
+void *la_ReadPointer(laUDF *udf){
+    u64bit result = 0;
+    if(!udf->FileContent){ fread(&result, sizeof(u64bit), 1, udf->DiskFile); }
+    else{ memcpy(&result, udf->FileContent + udf->Seek, sizeof(u64bit)); udf->Seek += sizeof(u64bit); }
+    return result;
+}
+real la_ReadFloat(laUDF *udf){
+    real result;
+    if(!udf->FileContent){ fread(&result, sizeof(real), 1, udf->DiskFile); }
+    else{ memcpy(&result, udf->FileContent + udf->Seek, sizeof(real)); udf->Seek += sizeof(real); }
+    return result;
+}
+void la_ReadString(laUDF *udf, char *buffer){
+    short len = la_ReadShort(udf);
+    if (len){
+        if(!udf->FileContent){ fread(buffer, sizeof(char) * len, 1, udf->DiskFile); }
+        else{ memcpy(buffer, udf->FileContent + udf->Seek, sizeof(char) * len); udf->Seek += sizeof(char) * len; }
+    }
+    buffer[len] = 0;
+}
+void la_ReadOnlyString(laUDF *udf, short len, char *buffer){
+    if(!udf->FileContent){ fread(buffer, sizeof(char) * len, 1, udf->DiskFile); }
+    else{ memcpy(buffer, udf->FileContent + udf->Seek, sizeof(char) * len); udf->Seek += sizeof(char) * len; }
+    buffer[len] = 0;
+}
+void la_ReadHyperData(laUDF *udf, void* HyperUserMem){
+    short NumUsers, i;
+    //void *CreatorInstance = la_ReadLong(udf);
+    laMemNodeHyper h_ = {0};
+    laMemNodeHyper *h=HyperUserMem?memGetHead(HyperUserMem, 0):&h_;
+    //la_UDFAppendPointerRecord(0, 0, &h->CreatedBy,CreatorInstance);
+
+    la_ReadString(udf, h->NUID.String);
+
+    h->TimeCreated.Year = la_ReadShort(udf);
+    h->TimeCreated.Month = la_ReadUByte(udf);
+    h->TimeCreated.Day = la_ReadUByte(udf);
+    h->TimeCreated.Hour = la_ReadUByte(udf);
+    h->TimeCreated.Minute = la_ReadUByte(udf);
+    h->TimeCreated.Second = la_ReadUByte(udf);
+}
+void la_PeekHyperUID(laUDF *udf, char* buf){
+    int pos=la_Tell(udf);
+    la_ReadString(udf, buf);
+    la_Seek(udf, pos);
+}
+void la_ReadBuffer(laUDF *udf, u64bit Size, void *Result){
+    if(!udf->FileContent){ fread(Result, Size, 1, udf->DiskFile); }
+    else{ memcpy(Result, udf->FileContent + udf->Seek, Size); udf->Seek += Size; }
+}
+void* la_ReadRaw(laUDF *udf, int* _sz){
+    int _size = la_ReadInt(udf);
+    if (_size){
+        void* data=calloc(1,_size);
+        la_ReadBuffer(udf, _size, data);
+        if(_sz) *_sz=_size;
+        return data;
+    } return 0;
+}
+
+
+void la_WriteSingleProperty(laUDF *udf, void *FromInstance, laProp *p){
+    la_WriteString(udf, p->Identifier);
+}
+void la_GetPropPackFullPath(laPropPack *pp, char *result){
+    char buf[1024], upbuf[1024]={0}; if(!pp){result[0]=0; return;}
+    laPropStep *ps;
+    buf[0] = L'\0';
+    upbuf[0] = 0;
+
+    if (pp->Go){
+        for (ps = pp->Go; ps; ps = ps->pNext){
+            //if (!ps->p||!ps->p->Identifier) strcat(buf, "?");
+            if(ps->Type=='.') strcat(buf, ps->p->Identifier);
+            if(ps->Type=='#' ||ps->Type=='@' ||ps->Type=='=') {char b2[2]={0}; b2[0]= ps->Type; strcat(buf, b2); strcat(buf, ps->p);}
+            if (ps->pNext && ps->pNext->Type=='.') strcat(buf, ".");
+        }
+    }else{
+        if(pp->LastPs){ if(pp->LastPs->p->Identifier) strcat(buf, pp->LastPs->p->Identifier); else { strcat(buf,"?"); } }
+        if (pp->RawThis && pp->RawThis->LastPs->p != pp->LastPs->p) strcat(buf, pp->LastPs->p->Identifier);
+    }
+
+    if (pp->RawThis){
+        la_GetPropPackFullPath(pp->RawThis, upbuf);
+        if (pp->RawThis->LastPs->p != pp->LastPs->p) strcat(upbuf, ".");
+        strcat(upbuf, buf);
+        strCopyFull(result, upbuf);
+    }else
+        strCopyFull(result, buf);
+}
+void la_GetPropPackPath(laPropPack *pp, char *result){
+    char buf[1024], upbuf[1024]={0};
+    laPropStep *ps;
+    buf[0] = L'\0';
+    upbuf[0] = 0;
+    char Sep[2] = {0};
+
+    for (ps = pp->Go; ps; ps = ps->pNext){
+        if (!ps->p->Identifier) break;
+        if (ps->Type == L'.' || !ps->Type) strcat(buf, ps->p->Identifier);
+        else
+            strcat(buf, ps->p);
+        if (ps->pNext) strcat(buf, (Sep[0] = ((laPropStep *)ps->pNext)->Type) ? Sep : ".");
+    }
+    strCopyFull(result, buf);
+}
+int la_ReadIntProp(laUDF *udf, laPropPack *pp){
+    laProp *p;
+    int Data[16] = {0};
+    int len = 0;
+    int i;
+    if (!pp){
+        int mode = la_ReadShort(udf);
+        if (mode == LA_UDF_ARRAY_MARK_32){
+            len = la_ReadShort(udf);
+            for (i = 0; i < len; i++)
+                la_ReadInt(udf);
+        }else
+            Data[0] = la_ReadInt(udf);
+        return Data[0];
+    }
+    p = pp->LastPs->p;
+    if (p->PropertyType & LA_PROP_ARRAY){
+        la_ReadShort(udf); //mark
+        len = la_ReadShort(udf);
+        //len = laGetArrayLength(pp);
+        for (i = 0; i < len; i++){
+            Data[i] = la_ReadInt(udf);
+        }
+        laReadIntArrayAllArray(pp, Data);
+    }else{
+        la_ReadShort(udf);
+        Data[0] = la_ReadInt(udf);
+        laReadInt(pp, Data[0]);
+    }
+    return Data[0];
+}
+real la_ReadFloatProp(laUDF *udf, laPropPack *pp){
+    laProp *p;
+    real Data[16] = {0};
+    int len = 0;
+    int i;
+    if (!pp){
+        int mode = la_ReadShort(udf);
+        if (mode == LA_UDF_ARRAY_MARK_64){
+            len = la_ReadShort(udf);
+            for (i = 0; i < len; i++)
+                la_ReadFloat(udf);
+        }else
+            Data[0] = la_ReadFloat(udf);
+        return Data[0];
+    }
+    p = pp->LastPs->p;
+    if (p->PropertyType & LA_PROP_ARRAY){
+        la_ReadShort(udf); //mark
+        len = la_ReadShort(udf);
+        //len = laGetArrayLength(pp);
+        for (i = 0; i < len; i++){
+            Data[i] = la_ReadFloat(udf);
+        }
+        if (pp) laReadFloatArrayAllArray(pp, Data);
+    }else{
+        la_ReadShort(udf);
+        Data[0] = la_ReadFloat(udf);
+        if (pp) laReadFloat(pp, Data[0]);
+    }
+    return Data[0];
+}
+void la_ReadStringProp(laUDF *udf, laPropPack *pp){
+    char buf[LA_RAW_CSTR_MAX_LEN]={0}; //XXX: long string not correct...
+    int len = 0;
+    int i;
+    buf[0] = 0;
+    la_ReadShort(udf);
+    la_ReadString(udf, buf);
+    if (pp) laReadString(pp, buf);
+}
+void la_ReadStringPropAsIdentifier(laUDF *udf, char *buf){
+    //char buf[LA_RAW_CSTR_MAX_LEN]={0};
+    int len = 0;
+    int i;
+    buf[0] = 0;
+    la_ReadShort(udf);
+    la_ReadString(udf, buf);
+}
+void la_WriteIntProp(laUDF *udf, laPropPack *pp){
+    laProp *p = pp->LastPs->p;
+    int Data[16] = {0};
+    int len = 0;
+    int i;
+    if (p->PropertyType & LA_PROP_ARRAY){
+        la_WriteShort(udf, LA_UDF_ARRAY_MARK_32);
+        laGetIntArray(pp, Data);
+        len = laGetArrayLength(pp);
+        la_WriteShort(udf, len);
+        for (i = 0; i < len; i++){
+            la_WriteInt(udf, Data[i]);
+        }
+    }else{
+        la_WriteShort(udf, LA_UDF_REGULAR_MARK_32);
+        Data[0] = laGetInt(pp);
+        la_WriteInt(udf, Data[0]);
+    }
+}
+void la_WriteFloatProp(laUDF *udf, laPropPack *pp){
+    laProp *p = pp->LastPs->p;
+    real Data[16] = {0};
+    int len = 0;
+    int i;
+    if (p->PropertyType & LA_PROP_ARRAY){
+        la_WriteShort(udf, LA_UDF_ARRAY_MARK_64);
+        laGetFloatArray(pp, Data);
+        len = laGetArrayLength(pp);
+        la_WriteShort(udf, len);
+        for (i = 0; i < len; i++){
+            la_WriteFloat(udf, Data[i]);
+        }
+    }else{
+        la_WriteShort(udf, LA_UDF_REGULAR_MARK_64);
+        Data[0] = laGetFloat(pp);
+        la_WriteFloat(udf, Data[0]);
+    }
+}
+void la_WriteStringProp(laUDF *udf, laPropPack *pp){
+    laProp *p = pp->LastPs->p;
+    char _buf[LA_RAW_CSTR_MAX_LEN]={0}; char* buf=_buf;
+    int len = 0;
+    int i;
+    buf[0] = 0;
+    la_WriteShort(udf, LA_UDF_STRING_MARK);
+    laGetString(pp, _buf, &buf);
+    la_WriteString(udf, buf);
+}
+void la_ReadEnumProp(laUDF *udf, laPropPack *pp, char* orig_string){
+    laProp *p;
+    int Data[16] = {0};
+    int len = 0;
+    int i;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+
+    if (!pp){
+        int mode = la_ReadShort(udf);
+        if (mode == LA_UDF_ARRAY_MARK_32){
+            len = la_ReadShort(udf);
+            for (i = 0; i < len; i++)
+                la_ReadString(udf, buf); //la_ReadInt(udf);
+        }else
+            la_ReadString(udf, buf); //la_ReadInt(udf);
+        if(orig_string)strcpy(orig_string, buf);
+        return;
+    }
+    p = pp->LastPs->p;
+
+    if (p->PropertyType & LA_PROP_ARRAY){
+        la_ReadShort(udf);
+        len = la_ReadShort(udf);
+        for (i = 0; i < len; i++){
+            la_ReadString(udf, buf);
+            Data[i] = laGetEnumFromIdentifier(p, buf)->Index;
+            //Data[i] = la_ReadInt(udf);
+        }
+        if (pp) laReadEnumArrayAll(pp, Data);
+    }else{
+        la_ReadShort(udf);
+        la_ReadString(udf, buf);
+        Data[0] = laGetEnumFromIdentifier(p, buf)->Index;
+        //Data[0] = la_ReadInt(udf);
+        if (pp) laReadEnum(pp, Data[0]);
+    }
+}
+void la_WriteEnumProp(laUDF *udf, laPropPack *pp){
+    laProp *p = pp->LastPs->p;
+    laEnumItem *Data[16] = {0};
+    int len = 0;
+    int i;
+    if (p->PropertyType & LA_PROP_ARRAY){
+        la_WriteShort(udf, (LA_UDF_ARRAY_MARK_32 | LA_UDF_STRING_MARK));
+        laGetEnumArray(pp, Data);
+        len = laGetArrayLength(pp);
+        la_WriteShort(udf, len);
+        for (i = 0; i < len; i++){
+            la_WriteString(udf, Data[i]->Identifier);
+            //la_WriteInt(udf, Data[i]->Index);
+        }
+    }else{
+        la_WriteShort(udf, LA_UDF_STRING_MARK);
+        Data[0] = laGetEnum(pp);
+        la_WriteString(udf, Data[0]->Identifier);
+        //la_WriteInt(udf, Data[0]->Index);
+    }
+}
+void la_ReadRawProp(laUDF *udf, laPropPack *pp){
+    la_ReadShort(udf);//mark
+    int _size=0;
+    void* data=la_ReadRaw(pp,&_size);
+    if (pp) laSetRaw(pp, data, _size); free(data);
+}
+void la_WriteRawProp(laUDF *udf, laPropPack *pp){
+    laProp *p = pp->LastPs->p;
+    void* data; int _size, IsCopy=0;
+    data=laGetRaw(pp, &_size, &IsCopy);
+    la_WriteShort(udf, LA_UDF_RAW_MARK);
+    la_WriteInt(udf,_size);
+    la_WriteSized(udf,data,_size);
+    if(IsCopy){ free(data); }
+}
+void la_WriteHyperData(laUDF *udf, void *HyperUserMem){
+    int loc = 0, res = 0, i = 0;
+    laItemUserLinker *iul;
+    laMemNodeHyper* h=memGetHead(HyperUserMem, 0);
+    //la_WriteLong(udf, h->CreatedBy);
+
+    la_WriteString(udf, h->NUID.String);
+
+    la_WriteShort(udf, h->TimeCreated.Year);
+    la_WriteUByte(udf, h->TimeCreated.Month);
+    la_WriteUByte(udf, h->TimeCreated.Day);
+    la_WriteUByte(udf, h->TimeCreated.Hour);
+    la_WriteUByte(udf, h->TimeCreated.Minute);
+    la_WriteUByte(udf, h->TimeCreated.Second);
+}
+laSharedTypeItem *la_ReferringToSharedResource(void *p){
+    laSharedTypeItem *sti;
+    for (sti = MAIN.SharedTypePointerSync.pFirst; sti; sti = sti->Item.pNext){
+        if (sti->Pointer == p)
+            return sti;
+    }
+    return 0;
+}
+void *la_FindSharedResouce(char *id){
+    laSharedTypeItem *sti;
+    for (sti = MAIN.SharedTypePointerSync.pFirst; sti; sti = sti->Item.pNext){
+        if (strSame(id, sti->ID))
+            return sti->Pointer;
+    }
+    return 0;
+}
+
+void la_AppendHyperRecord(laUDF *udf, void *HyperUserMem, laPropContainer* pc, u64bit Seek){
+    laUDFHyperRecordItem *hri = lstAppendPointerSized(&udf->HyperRecords, HyperUserMem, sizeof(laUDFHyperRecordItem));
+    hri->Seek = Seek;
+    hri->pc = pc;
+}
+
+void* la_NextH2Instance(laUDF* udf){
+    udf->CurrentH2Instance=udf->CurrentH2Instance?udf->CurrentH2Instance->Item.pNext:0;
+}
+
+int la_WriteProp(laUDF *udf, laPropPack *pp, int FromThis, int UseInstanceList){
+    laProp *p = pp->LastPs->p, *subp = 0;
+    laPropStep SubPS = {0};
+    laPropPack SubPP = {0};
+    laPropIterator pi = {0};
+    laSharedTypeItem *sti;
+    laMemNodeHyper *hi;
+    void *inst = 0;
+    u64bit pReserve = 0, pContinue = 0;
+    int ItemNum = 0, PropNum = 0;
+    int counted = 0;
+    long pEachCount;
+
+    SubPP.LastPs = &SubPS;
+
+    if (p->PropertyType == LA_PROP_OPERATOR) return 0;
+
+    if ((!pp->RawThis) || FromThis){
+        char FullPath[1024]={0};
+        FullPath[0] = 0;
+        la_GetPropPackFullPath(pp, FullPath);
+        la_WriteString(udf, FullPath);
+    }else{
+        la_WriteString(udf, p->Identifier);
+    }
+
+    switch (p->PropertyType){
+    case LA_PROP_SUB:
+        if (p->UDFIsRefer){
+            inst = laGetActiveInstanceStrict(p, pp->LastPs->UseInstance);
+            if (sti = la_ReferringToSharedResource(inst)){
+                la_WriteShort(udf, LA_UDF_SHARE_RESOURCE);
+                la_WriteString(udf, sti->ID);
+            }else{
+                if (!p->SubProp){
+                    p->SubProp = la_ContainerLookup(((laSubProp *)p)->TargetID);
+                }
+                if (p->SubProp->Hyper == 2){
+                    la_WriteShort(udf, LA_UDF_REFER | LA_UDF_HYPER_ITEM);
+                    if (!inst) la_WriteString(udf, "");
+                    else
+                        la_WriteString(udf, ((laMemNodeHyper *)memGetHead(inst,0))->NUID.String);
+                    udf->TotalRefs++;
+                }else{
+                    la_WriteShort(udf, LA_UDF_REFER);
+                    la_WritePointer(udf, inst);
+                }
+                pp->EndInstance = inst;
+            }
+            udf->TotalRefs++;
+        }else{
+            la_EnsureSubTarget(p,0);
+
+            la_WriteShort(udf, LA_UDF_COLLECTION);
+            pReserve = la_Tell(udf); la_WriteInt(udf, 0);   //num items
+            if (((laSubProp*)p)->GetType) la_WriteInt(udf, LA_UDF_VARIABLE_NODE_SIZE);
+            else la_WriteInt(udf, LA_UDF_FIXED_NODE_SIZE);
+            la_WriteShort(udf, LA_UDF_ACTIVE);
+            la_WritePointer(udf, laGetActiveInstance(p, pp->LastPs->UseInstance, &pi));
+
+            if (FromThis){
+                inst = pp->EndInstance;
+            }else{
+                inst = laGetInstance(p, pp->LastPs->UseInstance, &pi);
+                pp->EndInstance = inst;
+            }
+
+            while (inst){
+                laPropContainer* pc=p->SubProp;
+                if (((laSubProp*)p)->GetType){ pc=((laSubProp*)p)->GetType(inst); la_WriteString(udf, pc->Identifier); }
+
+                if (pc->Hyper == 2){
+                    if(UseInstanceList&&inst!=udf->CurrentH2Instance->Instance){
+                        inst = laGetNextInstance(p, inst, &pi); pp->EndInstance = inst; continue;}
+                    hi = inst;
+                    la_WriteShort(udf, LA_UDF_HYPER_ITEM);
+                    la_AppendHyperRecord(udf, inst, p->SubProp, la_Tell(udf));
+                    la_WriteHyperData(udf, inst);
+                    memMarkClean(inst);
+                }else{
+                    la_WriteShort(udf, LA_UDF_ITEM);
+                }
+                
+                ItemNum++;
+
+                la_WritePointer(udf, inst);
+                la_WriteInt(udf, laGetUiState(p, pp->LastPs->UseInstance));
+
+                PropNum=0; pEachCount = la_Tell(udf); la_WriteShort(udf, 0);
+                for (subp = pc->Props.pFirst; subp; subp = subp->Item.pNext){
+                    if (subp->UDFIgnore) continue;
+                    SubPP.RawThis = pp;
+                    SubPS.p = subp;
+                    SubPS.UseInstance = inst;
+                    if (la_WriteProp(udf, &SubPP, 0, UseInstanceList)) PropNum++;
+                }
+
+                if (FromThis){ inst = 0; }else{
+                    inst = laGetNextInstance(p, inst, &pi);
+                    pp->EndInstance = inst;
+                    if(UseInstanceList&&pc->Hyper==2){ la_NextH2Instance(udf); if(!udf->CurrentH2Instance) inst=0; }
+                }
+                pContinue = la_Tell(udf);
+                la_Seek(udf, pEachCount); la_WriteShort(udf, PropNum);
+                la_Seek(udf, pContinue);
+            }
+            pContinue = la_Tell(udf);
+            la_Seek(udf, pReserve); la_WriteInt(udf, ItemNum);
+            la_Seek(udf, pContinue);
+        }
+        break;
+    case LA_PROP_INT:
+    case LA_PROP_ARRAY | LA_PROP_INT:
+        la_WriteIntProp(udf, pp);
+        break;
+    case LA_PROP_FLOAT:
+    case LA_PROP_ARRAY | LA_PROP_FLOAT:
+        la_WriteFloatProp(udf, pp);
+        break;
+    case LA_PROP_STRING:
+        la_WriteStringProp(udf, pp);
+        break;
+    case LA_PROP_ENUM:
+    case LA_PROP_ARRAY | LA_PROP_ENUM:
+        la_WriteEnumProp(udf, pp);
+        break;
+    case LA_PROP_RAW:
+        la_WriteRawProp(udf, pp);
+        break;
+    default:
+        break;
+    }
+    return 1;
+}
+
+void la_AddPostReadNode(void *Instance, laContainerPostReadFunc Func){
+    laUDFPostRead *upr = lstAppendPointerSized(&MAIN.PostReadNodes, Instance, sizeof(laUDFPostRead));
+    upr->Instance = Instance;
+    upr->Func = Func;
+    lstAppendItem(&MAIN.PostReadNodes, upr);
+}
+laUDFContentNode *la_AppendUDFContentNode(laUDFContentInstance *Parent, laPropPack *ForMe, u64bit FileSeek){
+    char FullPath[256]={0};
+    laUDFContentNode *ucn = CreateNew(laUDFContentNode);
+    FullPath[0] = 0;
+
+    laProp *p = ForMe->LastPs->p;
+
+    strSafeSet(&ucn->Identifier, p->Identifier);
+    sprintf(FullPath, "%s.%s", Parent->Parent->FullPath->Ptr, p->Identifier);
+    strSafeSet(&ucn->FullPath, FullPath);
+    ucn->PP.Go = &ucn->FakePS;
+    ucn->PP.LastPs = &ucn->FakePS;
+    ucn->FakePS.p = p;
+    ucn->FakePS.Type = L'.';
+    ucn->PP.RawThis = &Parent->Parent->PP;
+    ucn->Parent = Parent;
+    ucn->FileSeek = FileSeek;
+
+    lstAppendItem(&Parent->Children, ucn);
+
+    return ucn;
+}
+laUDFContentInstance *la_AppendUDFContentInstance(laUDFContentNode *Parent, u64bit FileSeek){
+    laUDFContentInstance *uci = CreateNew(laUDFContentInstance);
+
+    uci->FileSeek = FileSeek;
+    uci->Parent = Parent;
+    strSafePrint(&uci->Identifier,"Instance at seek 0x%0x", FileSeek);
+
+    lstAppendItem(&Parent->Instances, uci);
+
+    return uci;
+}
+void la_DestroyUDFContentNodeTreeRecursive(laUDFContentNode *ucn, int FreeRoot){
+    laUDFContentNode *ucni, *NextUCNI;
+    laUDFContentInstance *ucii, *NextUCII;
+    for (ucii = ucn->Instances.pFirst; ucii; ucii = NextUCII){
+        NextUCII = ucii->Item.pNext;
+        for (ucni = ucii->Children.pFirst; ucni; ucni = NextUCNI){
+            NextUCNI = ucni->Item.pNext;
+            strSafeDestroy(&ucii->Identifier);
+            lstRemoveItem(&ucii->Children, ucni);
+            la_DestroyUDFContentNodeTreeRecursive(ucni, 1);
+        }
+        lstRemoveItem(&ucn->Instances, ucii);
+        FreeMem(ucii);
+    }
+    strSafeDestroy(&ucn->Identifier);
+    strSafeDestroy(&ucn->FullPath);
+    if (FreeRoot) FreeMem(ucn);
+}
+
+void *la_GetReadDBInstNUID(char *ReferReadNUID){
+    if (!ReferReadNUID) return 0;
+    laListHandle *l = hsh16MDoHashNUID(&MAIN.DBInst2, ReferReadNUID);
+    for (laMemNodeHyper* m = l->pFirst; m; m = m->Item.pNext){
+        if (!strcmp(ReferReadNUID, m->NUID.String))
+            return ((unsigned char*)m)+sizeof(laMemNodeHyper);
+    }
+    return 0;
+}
+void *la_GetReadDBInstPtr(void *ReferRead){
+    if (!ReferRead) return 0;
+    laListHandle *l = hsh16MDoHashLongPtr(&MAIN.DBInst1, ReferRead);
+    for (laMemNode* m = l->pFirst; m; m = m->Item.pNext){
+        if (ReferRead == m->ReadInstance)
+            return ((unsigned char*)m)+sizeof(laMemNode);
+    }
+    return 0;
+}
+void la_AddDataInst(void *ReadInstance, char *ReadNUID, void *ActualInstance){
+    laListHandle* l=0;
+    void* head=memGetHead(ActualInstance, 0);
+
+    if (ReadNUID) l = hsh16MDoHashNUID(&MAIN.DBInst2, ReadNUID);
+    else { l = hsh16MDoHashLongPtr(&MAIN.DBInst1, ReadInstance); ((laMemNode*)head)->ReadInstance = ReadInstance; }
+
+    lstAppendItem(l, head);
+}
+
+laPtrSync *la_AddPtrSyncDirect(void *Refer, void *Parent, laProp *Sub){
+    laPtrSync *ps = memAcquireSimple(sizeof(laPtrSync));
+    ps->RefDB = Refer;
+    ps->Parent = Parent;
+    ps->Prop = Sub;
+
+    return ps;
+}
+laPtrSync *la_AddPtrSync(char *ReferReadNUID, void *ActualParent, laProp *Sub){
+    laPtrSync *ps = memAcquireSimple(sizeof(laPtrSync));
+    ps->RefDB = la_GetReadDBInstNUID(ReferReadNUID);
+    ps->Parent = ActualParent; //la_GetWriteDBInst(ActualParent);
+    ps->Prop = Sub;
+    return ps;
+}
+laPtrSyncCommand *la_AddPtrSyncCommand(void *ReadRefer, void *ParentInst, char *ReadNUID, laProp *Sub){
+    laPtrSyncCommand *psc = memAcquireSimple(sizeof(laPtrSyncCommand));
+    psc->Target = la_AddPtrSyncDirect(0, ParentInst, Sub);
+    psc->ReadInstance = ReadRefer;
+    if (ReadNUID) strcpy(psc->ReadNUID.String, ReadNUID);
+    lstAppendItem(&MAIN.PtrSyncCommandList, psc);
+    return psc;
+}
+
+void la_ResetInstance(void* inst, laPropContainer* pc);
+
+void la_ExecutePtrSyncCommand(int Mode){
+    int i;
+    laPtrSyncCommand *psc;
+    laPtrSync *ps;
+    void *dbi;
+    laListHandle *lps, *ldbi;
+    laListHandle L2 = {0};
+    int FailCount = 0, AllCount = 0;
+
+    while (psc = lstPopItem(&MAIN.PtrSyncCommandList)){
+        ps = psc->Target;
+        if (psc->ReadNUID.String[0]) dbi = la_GetReadDBInstNUID(psc->ReadNUID.String);
+        elif (psc->ReadInstance) dbi = la_GetReadDBInstPtr(psc->ReadInstance); // should remove from hash and clear readinst when get this.
+
+        if (dbi){
+            //if (Mode == LA_UDF_APPEND)dbi->ReadInst = dbi->ActualInst;
+            ps->RefDB = dbi;
+            laSetActiveInstance(ps->Prop, ps->Parent, dbi);
+        }else{
+            FailCount++;
+        }
+        AllCount++;
+        memFree(psc);
+    }
+
+    logPrint("Reference Match: Total %d, Failed %d\n", AllCount, FailCount);
+}
+
+int la_ExtractFakeProp(laUDF *udf){
+    char buf[LA_RAW_CSTR_MAX_LEN] = {0};
+    void *Instance = 0;
+    void *ReadInstance;
+    int ReadState;
+    int NumItems;
+    short PropNumPerItem;
+    void *ActiveInstance;
+    int i, j;
+    int ItemType;
+    short mode, len;
+    int VariableNodeSize;
+    short PreMode;
+
+    mode = la_ReadShort(udf);
+    switch (mode){
+    case LA_UDF_REGULAR_MARK_32:
+        la_ReadInt(udf);
+        break;
+    case LA_UDF_REGULAR_MARK_64:
+        la_ReadFloat(udf);
+        break;
+    case (LA_UDF_ARRAY_MARK_32 | LA_UDF_STRING_MARK):
+        len = la_ReadShort(udf);
+        for (i = 0; i < len; i++)
+            la_ReadString(udf, buf);
+        break;
+    case LA_UDF_ARRAY_MARK_32:
+        len = la_ReadShort(udf);
+        for (i = 0; i < len; i++)
+            la_ReadInt(udf);
+        break;
+    case LA_UDF_ARRAY_MARK_64:
+        len = la_ReadShort(udf);
+        for (i = 0; i < len; i++)
+            la_ReadFloat(udf);
+        break;
+    case LA_UDF_STRING_MARK:
+        la_ReadString(udf, buf);
+        break;
+    case LA_UDF_SHARE_RESOURCE:
+        la_ReadString(udf, buf);
+        break;
+    case LA_UDF_REFER:
+        la_ReadPointer(udf);
+        break;
+    case (short)(LA_UDF_REFER | LA_UDF_HYPER_ITEM):
+        la_ReadString(udf, buf);
+        break;
+    case LA_UDF_COLLECTION:
+        NumItems = la_ReadInt(udf);
+        VariableNodeSize = la_ReadInt(udf);
+        VariableNodeSize = (VariableNodeSize == LA_UDF_VARIABLE_NODE_SIZE) ? 1 : 0;
+        la_ReadShort(udf); //active mark
+        ActiveInstance = la_ReadPointer(udf);
+
+        for (i = 0; i < NumItems; i++){
+            if(VariableNodeSize){ la_ReadString(udf,buf); }
+            ItemType = la_ReadShort(udf);
+            if (ItemType == LA_UDF_HYPER_ITEM){ la_ReadHyperData(udf, 0); }
+            ReadInstance = la_ReadPointer(udf);
+            ReadState = la_ReadInt(udf);
+            PropNumPerItem=la_ReadShort(udf);
+            for (j = 0; j < PropNumPerItem; j++){
+                la_ReadString(udf, buf);
+                la_ExtractFakeProp(udf);
+            }
+        }
+        break;
+    default:
+        ReadState = ReadState;
+        break;
+    }
+    return 0;
+}
+int la_ExtractProp(laUDF *udf, laManagedUDF* mUDF, laPropPack *pp, void *ParentInst, int Mode, laUDFContentNode *Parent){
+    laPropStep SubPS = {0};
+    laPropPack SubPP = {0};
+    char buf[LA_RAW_CSTR_MAX_LEN] = {0};
+    laProp *p = pp->LastPs->p, *subp;
+    short SubMode, ItemType = 0;
+    void *Instance = 0;
+    void *ReadInstance;
+    int ReadState;
+    int NumItems;
+    short PropNumPerItem;
+    void *ActiveInstance;
+    short PreReadMode;
+    int i, j;
+    int VariableNodeSize;
+    char NodeType[128]={0};
+    int EStatus = 0;
+    laUDFContentInstance *uci;
+    real ReadF;
+    int ReadI;
+    int IsExceptionNode = 0;
+
+    SubPP.LastPs = &SubPS;
+
+    switch (p->PropertyType){
+    case LA_PROP_SUB:
+        la_EnsureSubTarget(p, 0);
+
+        SubMode = la_ReadShort(udf);
+        if (SubMode == LA_UDF_SHARE_RESOURCE){
+            if (!Parent){
+                la_ReadString(udf, buf);
+                laSetActiveInstance(p, pp->LastPs->UseInstance, la_FindSharedResouce(buf));
+            }
+        }elif (SubMode == LA_UDF_REFER){
+            Instance = la_ReadPointer(udf);
+            if (Instance && !Parent && p->Offset>=0){
+                if (p->OffsetIsPointer) la_AddPtrSyncCommand(Instance, ParentInst, 0, p);
+                else la_AddDataInst(Instance, 0, ((BYTE *)pp->LastPs->UseInstance + p->Offset));
+            }
+        }elif (SubMode == (short)(LA_UDF_REFER | LA_UDF_HYPER_ITEM)){
+            char NUID[32]={0};
+            NUID[0] = 0;
+            la_ReadString(udf, NUID);
+            if (NUID[0] && !Parent){
+                la_AddPtrSyncCommand(0, ParentInst, NUID, p);
+            }
+        }elif (SubMode == LA_UDF_COLLECTION){
+            laProp **PreList = 0; void *ThisDBInst = 0;
+
+            NumItems = la_ReadInt(udf);
+            VariableNodeSize = la_ReadInt(udf);
+            VariableNodeSize = (VariableNodeSize == LA_UDF_VARIABLE_NODE_SIZE) ? 1 : 0;
+            la_ReadShort(udf); //active mark
+            ActiveInstance = la_ReadPointer(udf);
+
+            if (NumItems == 0) break;
+
+            if (p->UDFNoCreate){
+                laPropIterator PI = {0};
+
+                ItemType = la_ReadShort(udf);
+                if (Parent) uci = la_AppendUDFContentInstance(Parent, la_Tell(udf));
+
+                Instance = laGetInstance(p, pp->LastPs->UseInstance, &PI);
+
+                if (ItemType == LA_UDF_HYPER_ITEM){
+                    if (p->SubProp->Hyper == 2){
+                        if (!Parent && !IsExceptionNode) la_ReadHyperData(udf, Instance);
+                        else la_ReadHyperData(udf, 0);
+                        if(mUDF) memAssignRef(Instance, &((laMemNodeHyper*)memGetHead(Instance, 0))->FromFile, mUDF);
+                        memMarkClean(Instance);
+                    }else la_ReadHyperData(udf, 0);
+                }
+
+                if (!Parent && p->SubProp->PostRead) la_AddPostReadNode(Instance, p->SubProp->PostRead);
+
+                ReadInstance = la_ReadPointer(udf);
+                ReadState = la_ReadInt(udf);
+
+                if (!Parent) ThisDBInst=Instance;
+
+                PropNumPerItem = la_ReadShort(udf);
+                for (j = 0; j < PropNumPerItem; j++){
+                    int result; laUDFContentNode *ucn;
+                    la_ReadString(udf, buf);
+                    subp = la_PropLookup(&p->SubProp->Props, buf);
+                    SubPP.RawThis = pp;
+                    SubPS.p = subp;
+                    SubPS.UseInstance = Instance;
+                    if (!subp->SubProp){ subp->SubProp = la_ContainerLookup(((laSubProp *)subp)->TargetID); }
+                    if (Parent && subp->PropertyType == LA_PROP_SUB){
+                        if (!subp->UDFIsRefer && !IsExceptionNode){
+                            ucn = la_AppendUDFContentNode(uci, &SubPP, la_Tell(udf));
+                            result = la_ExtractProp(udf, mUDF, &SubPP, ThisDBInst, Mode, ucn);
+                        }else{ result = la_ExtractFakeProp(udf);}
+                    }else{
+                        result = IsExceptionNode ? result = la_ExtractFakeProp(udf) : la_ExtractProp(udf, mUDF, &SubPP, ThisDBInst, Mode, Parent);
+                    }
+                    EStatus = result ? result : EStatus;
+                }
+                if (!Parent && p->SubProp->PostReadIm) p->SubProp->PostReadIm(Instance);
+            }else{
+                if(Mode==LA_UDF_MODE_APPEND && p->UDFIsSingle){
+                    logPrint("[Note] Mode is APPEND but property '%s' only allows one instance, will overwrite.\n", p->Identifier);
+                }
+                for (i = 0; i < NumItems; i++){
+                    int RealSize=0; laUDF *SaveUDF = 0; int SaveItemType = 0;IsExceptionNode = 0; Instance=0;
+
+                    laPropContainer* pc=p->SubProp;
+                    if(VariableNodeSize){ la_ReadString(udf, NodeType); pc=la_ContainerLookup(NodeType);
+                        if(!pc){pc=p->SubProp;} RealSize=pc->NodeSize; 
+                    }
+
+                    ItemType = (short)la_ReadShort(udf);
+
+                    if (Parent) uci = la_AppendUDFContentInstance(Parent, la_Tell(udf));
+
+                    int replaced=0;
+                    if (udf){
+                        RealSize = RealSize ? RealSize : p->SubProp->NodeSize;
+                        if (!Parent && !IsExceptionNode){
+                            if (p->UDFIsSingle && p->UDFNoCreate){ Instance = pp->EndInstance; }
+                            else{
+                                // if overwrite, find the instance here for hyper2, if not hyper 2 then notice can't overwrite.
+                                if (pc->Hyper == 2){
+                                    if(Mode==LA_UDF_MODE_OVERWRITE && ItemType == LA_UDF_HYPER_ITEM){
+                                        laUID uid; la_PeekHyperUID(udf, &uid.String);
+                                        Instance = la_GetReadDBInstNUID(uid.String);
+                                        if(Instance){ la_ResetInstance(Instance, pc); replaced=1; }
+                                        else{ logPrint("[Note] Hyper2 item [%s] from property '%s' hasn't been loaded yet, will append.\n", uid.String, p->Identifier); }
+                                    }
+                                    if(!Instance) Instance = memAcquireHyperNoAppend(RealSize);
+                                    memMarkClean(Instance);
+                                }elif (pc->Hyper == 1) Instance = memAcquire(RealSize);
+                                else Instance = memAcquireSimple(RealSize);
+                            }
+                        }
+
+                        if (ItemType == LA_UDF_HYPER_ITEM){
+                            if (pc->Hyper == 2){
+                                la_ReadHyperData(udf, Instance);
+                                if(mUDF) memAssignRef(Instance, &((laMemNodeHyper*)memGetHead(Instance, 0))->FromFile, mUDF);
+                            }
+                            else la_ReadHyperData(udf, 0);
+                        }
+                        if (!Parent && !IsExceptionNode){
+                            if (pc->PostRead) la_AddPostReadNode(Instance, pc->PostRead);
+                        }
+
+                        ReadInstance = la_ReadPointer(udf);
+                        ReadState = la_ReadInt(udf);
+
+                        if (!Parent && !IsExceptionNode && !replaced){
+                            la_AddDataInst(ReadInstance, pc->Hyper == 2 ? ((laMemNodeHyper *)memGetHead(Instance,0))->NUID.String : 0, Instance);
+                        }
+                        ThisDBInst = Instance;
+
+                        PropNumPerItem = la_ReadShort(udf);
+                        for (j = 0; j < PropNumPerItem; j++){
+                            u64bit ThisSeek;
+                            la_ReadString(udf, buf);
+                            subp = la_PropLookup(&pc->Props, buf);
+                            if (!subp || subp->UDFIgnore) la_ExtractFakeProp(udf);
+                            else{
+                                int result; laUDFContentNode *ucn;
+                                ThisSeek = la_Tell(udf);
+                                SubPP.RawThis = pp; SubPS.p = subp; SubPS.UseInstance = Instance;
+                                la_EnsureSubTarget(subp, 0);
+                                if (Parent && subp->PropertyType == LA_PROP_SUB && subp->SubProp){
+                                    if (!subp->UDFIsRefer && !IsExceptionNode){
+                                        ucn = la_AppendUDFContentNode(uci, &SubPP, ThisSeek);
+                                        result = la_ExtractProp(udf, mUDF, &SubPP, ThisDBInst, Mode, ucn);
+                                    }else{ result = la_ExtractFakeProp(udf); }
+                                }else{
+                                    result = IsExceptionNode ? la_ExtractFakeProp(udf) : la_ExtractProp(udf, mUDF, &SubPP, ThisDBInst, Mode, Parent);
+                                }
+                                EStatus = result ? result : EStatus;
+                            }
+                        }
+
+                        if (!Parent && !IsExceptionNode && !replaced){
+                            if (pc->PostReadIm) pc->PostReadIm(Instance);
+                            if (pp->LastPs->UseInstance){
+                                if (!p->UDFIsSingle){
+                                    if (((laSubProp *)p)->ListHandleOffset){
+                                        lstAppendItem((BYTE *)pp->LastPs->UseInstance + ((laSubProp *)p)->ListHandleOffset, Instance);
+                                    }else{ lstAppendItem(&pc->FailedNodes, Instance); EStatus = 1; }
+                                }else{ if (!p->UDFNoCreate){ laSetActiveInstance(p, pp->LastPs->UseInstance, Instance); } }
+                                if (ReadInstance == ActiveInstance) laSetActiveInstance(p, pp->LastPs->UseInstance, Instance);
+                            }else{
+                                if (!p->UDFIsSingle){ lstAppendItem(&pc->FailedNodes, Instance); EStatus = 1; }
+                            }
+                        }
+                    }
+                }
+            }
+            if (PreList) memFree(PreList);
+        }
+        break;
+    case LA_PROP_INT:
+    case LA_PROP_ARRAY | LA_PROP_INT:
+        ReadI = la_ReadIntProp(udf, Parent ? 0 : pp);
+        if (Parent && p->Tag & LA_AS_IDENTIFIER){
+            sprintf(buf, "%d", ReadI); strSafeSet(&((laUDFContentInstance *)Parent->Instances.pLast)->Identifier, buf);
+        }
+        break;
+    case LA_PROP_FLOAT:
+    case LA_PROP_ARRAY | LA_PROP_FLOAT:
+        ReadF = la_ReadFloatProp(udf, Parent ? 0 : pp);
+        if (Parent && p->Tag & LA_AS_IDENTIFIER){
+            sprintf(buf, "%lf", ReadF); strSafeSet(&((laUDFContentInstance *)Parent->Instances.pLast)->Identifier, buf);
+        }
+        break;
+    case LA_PROP_STRING:
+        if (Parent && p->Tag & LA_AS_IDENTIFIER){
+            la_ReadStringPropAsIdentifier(udf, buf); strSafeSet(&((laUDFContentInstance *)Parent->Instances.pLast)->Identifier, buf);
+        }else{
+            la_ReadStringProp(udf, Parent ? 0 : pp);
+        }
+        break;
+    case LA_PROP_ENUM:
+    case LA_PROP_ARRAY | LA_PROP_ENUM:
+        la_ReadEnumProp(udf, Parent ? 0 : pp, buf);
+        if (Parent && p->Tag & LA_AS_IDENTIFIER){
+            strSafeSet(&((laUDFContentInstance *)Parent->Instances.pLast)->Identifier, buf); }
+        break;
+    case LA_PROP_RAW:
+        la_ReadRawProp(udf, pp);
+        break;
+    default:
+        break;
+    }
+    return EStatus;
+}
+
+int la_RematchPointers(int Mode){
+    laUDFPostRead *uprd;
+    void* inst;
+
+    la_ExecutePtrSyncCommand(Mode);
+
+    while(uprd=lstPopItem(&MAIN.PostReadNodes)){ uprd->Func(uprd->Instance); free(uprd); }
+    while(inst=lstPopPointer(&MAIN.RenewHyper2s)){ memMakeHyperData(memGetHead(inst,0)); }
+}
+
+int laPackUDF(laUDF *udf, int UseInstanceList){
+    laUDFPropSegment *ps;
+    short NumSegments = 0;
+    u64bit RefPos;
+    u64bit nuidSeekRef;
+    u64bit nuidActualSeek;
+    char Root[1024]={0};
+    char FilePath[1024]={0};
+
+    udf->DiskFile = fopen(udf->FileName->Ptr, "wb");
+    if (!udf->DiskFile) return 0;
+
+    la_WriteOnlyMBString(udf, LA_UDF_IDENTIFIER);
+
+    // reserved for extension switches.
+    la_WritePointer(udf, 0);
+
+    RefPos = la_Tell(udf);
+    la_WriteLong(udf, 0); //How Many Refs.
+    la_WriteShort(udf, udf->NumSegmets);
+
+    la_WriteLong(udf, LA_UDF_NUID_SEEK);
+    nuidSeekRef = la_Tell(udf);
+    la_WritePointer(udf, 0); //Seek pos for nuid list;
+
+    printf("Packing %s:\n", udf->FileName->Ptr);
+
+    udf->CurrentH2Instance=udf->H2Instances.pFirst;
+
+    while (ps = lstPopItem(&udf->PropsToOperate)){
+        printf("    %-15s\n", ps->Path ? ps->Path->Ptr : ps->PPP->LastPs->p->Identifier);
+        la_WriteProp(udf, ps->PPP ? ps->PPP : &ps->PP, ps->PPP ? 1 : 0, UseInstanceList);
+        la_FreePropStepCache(ps->PP.Go);
+        strSafeDestroy(&ps->Path);
+        FreeMem(ps);
+    }
+    printf("[ALL DONE]\n");
+
+    nuidActualSeek = la_Tell(udf);
+
+    la_WriteHyperRecords(udf);
+
+    la_Seek(udf, RefPos);
+    la_WriteLong(udf, udf->TotalRefs);
+
+    la_Seek(udf, nuidSeekRef);
+    la_WritePointer(udf, nuidActualSeek);
+
+    udf->Modified = 0;
+
+    laCloseUDF(udf);
+
+    return 1;
+}
+int laExtractUDF(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *Parent){
+    char Identifier[9] = {0};
+    char buf[1024]={0};
+    short Version, NumSegments;
+    //laPropStep SubPS = { 0 };
+    int PointerBits;
+    laPropPack SubPP = {0};
+    int i;
+    int EStatus = 0;
+    u64bit SeekRef;
+    int IsPart;
+    laUDFContentNode *ucni = Parent;
+
+    la_ReadBuffer(udf, sizeof(LA_UDF_IDENTIFIER) - 1, Identifier);
+
+    // reserved for extension switches.
+    la_ReadPointer(udf);
+
+    /*udf->TotalRefs = */ la_ReadLong(udf);
+    NumSegments = la_ReadShort(udf);
+    la_ReadLong(udf); //seek mark
+    SeekRef = la_ReadPointer(udf);
+
+    logPrintNew("Extracting UDF %s:\n", udf->FileName->Ptr);
+
+    //MAIN.NextPendingPointer = 0;
+    //MAIN.PendingPointers = CreateNewBuffer(laUDFPointerRecord, udf->TotalRefs);
+
+    //SubPP.LastPs = &SubP;
+
+    if (!udf->PropsToOperate.pFirst){ //Extract All
+        for (i = 0; i < NumSegments; i++){
+            laUDFContentNode *ucn;
+            laUDFContentInstance *uci;
+            void *dbi = 0;
+            int result;
+            int LastOffset;
+            la_ReadString(udf, buf);
+            LastOffset = strlen(buf) - 1;
+            buf[LastOffset] = buf[LastOffset] == L'.' ? 0 : buf[LastOffset];
+            logPrint("    Prop Segment \"%s\" ...", buf);
+            la_GetPropFromPath(&SubPP, 0, buf, 0);
+            la_StepPropPack(&SubPP);
+            if (Parent){
+                ucni = CreateNew(laUDFContentNode);
+                la_GetPropFromPath(&ucni->PP, 0, buf, 0);
+                la_StepPropPack(&ucni->PP);
+                strSafeSet(&ucni->FullPath, buf);
+                strSafeSet(&ucni->Identifier, buf);
+                ucni->FileSeek = la_Tell(udf);
+                lstAppendItem(Parent, ucni);
+            }
+            dbi = SubPP.EndInstance; //la_GetWriteDBInst(SubPP.EndInstance);
+            result = la_ExtractProp(udf, mUDF, &SubPP, dbi, Mode, ucni);
+            EStatus = result ? result : EStatus;
+            laNotifyUsersPP(&SubPP);
+            logPrint("[Done]\n", buf);
+            la_FreePropStepCache(SubPP.Go);
+            SubPP.Go = 0;
+        }
+    }
+
+    la_RematchPointers(Mode);
+
+    return EStatus;
+}
+
+
+laManagedUDF* la_FindManagedUDF(char* FileName){
+    for(laManagedUDF* m=MAIN.ManagedUDFs.pFirst;m;m=m->Item.pNext){
+        if(m->udf&&m->udf->FileName&&!strcmp(m->udf->FileName->Ptr,FileName)) return m;
+    }
+    return 0;
+}
+laManagedUDF* la_EnsureManagedUDF(char* FileName, int PutAtTop){
+    laManagedUDF* m;
+    if(!(m=la_FindManagedUDF(FileName))){
+        m=memAcquire(sizeof(laManagedUDF)); strSafeSet(&m->BaseName, strGetLastSegment(FileName,'/'));
+        if(PutAtTop) lstPushItem(&MAIN.ManagedUDFs, m); else lstAppendItem(&MAIN.ManagedUDFs, m);
+    }
+    return m;
+}
+void la_MakeDummyManagedUDF(){
+    MAIN.DummyManageUDF=la_EnsureManagedUDF("< Save as a new file >", 1);
+}
+void laSaveProp(char* path){
+    if(!path || !path[0]) return; laManagedSaveProp* msp=0;
+    for(laManagedSaveProp* m=MAIN.ManagedSaveProps.pFirst;m;m=m->Item.pNext){
+        if(!strcmp(m->Path->Ptr,path)){ msp=m; break; }
+    }
+    if(!msp){ msp=memAcquireSimple(sizeof(laManagedSaveProp)); lstAppendItem(&MAIN.ManagedSaveProps, msp); }
+    strSafeSet(&msp->Path, path);
+}
+void laClearSaveProp(){
+    laManagedSaveProp* m; while(m=lstPopItem(&MAIN.ManagedSaveProps)) { strSafeDestroy(&m->Path); memFree(m); }
+}
+
+int la_ScanForModifiedRecursive(laPropPack* pp, int ReturnIfAnyMod, int ReturnIfAnyEmpty, int* rempty, int RegisterToUDF){
+    int result=0;
+    laProp* p=pp->LastPs->p; laPropIterator pi={0};
+    if(p->PropertyType!=LA_PROP_SUB || p->UDFIsRefer || p->UDFIgnore) return 0;
+    la_EnsureSubTarget(p, 0); //if(p->SubProp && p->SubProp->Hyper!=2) return 0;
+    void* inst = laGetInstance(p, pp->LastPs->UseInstance, &pi);
+    while(inst){
+        laPropContainer* pc=la_EnsureSubTarget(p, inst);
+        if(pc->Hyper!=2){
+            laPropPack spp={0}; laPropStep sps={0}; spp.LastPs=&sps;
+            for(laProp* sp=pc->Props.pFirst;sp;sp=sp->Item.pNext){
+                sps.UseInstance=inst; sps.p=sp;
+                if(sp->PropertyType==LA_PROP_SUB) {
+                    result|=la_ScanForModifiedRecursive(&spp, ReturnIfAnyMod, ReturnIfAnyEmpty, rempty, RegisterToUDF);
+                    if((ReturnIfAnyMod||ReturnIfAnyEmpty)&&result)return result;
+                }
+            }
+        }else{
+            laMemNodeHyper* m = memGetHead(inst,0);
+            if(!m->FromFile || m->FromFile==MAIN.DummyManageUDF){ result|=1; if(rempty)*rempty|=1; if((ReturnIfAnyMod||ReturnIfAnyEmpty)&&result)return result; }
+            if(RegisterToUDF&&m->FromFile&&m->FromFile->udf){ la_IncludeHyper2Instance(m->FromFile->udf, pc, inst); }
+            if(m->Modified){
+                if(m->FromFile && m->FromFile->udf){ m->FromFile->udf->Modified=1; }
+                result|=1; if(ReturnIfAnyMod&&result)return result;
+            }
+        }
+        inst=laGetNextInstance(p,inst,&pi);
+    }
+    return result;
+}
+int laRegisterModifications(int ReturnIfAnyMod, int ReturnIfAnyEmpty, int* rempty, int RegisterToUDF){
+    int result=0, registered; if(RegisterToUDF){ReturnIfAnyMod=ReturnIfAnyEmpty=0;}
+    for(laManagedUDF* m=MAIN.ManagedUDFs.pFirst;m;m=m->Item.pNext){
+        if(!m->udf)continue;
+        m->udf->Modified=0; 
+        la_ClearHyper2Instances(m->udf);
+    }
+    for(laManagedSaveProp* msp=MAIN.ManagedSaveProps.pFirst;msp;msp=msp->Item.pNext){
+        laPropPack PP={0}; registered=0;
+        if(msp->Path&&msp->Path->Ptr&&la_GetPropFromPath(&PP, 0, msp->Path->Ptr, 0)){
+            la_StepPropPack(&PP);
+            result|=la_ScanForModifiedRecursive(&PP, ReturnIfAnyMod, ReturnIfAnyEmpty, rempty, RegisterToUDF);
+            for(laManagedUDF* m=MAIN.ManagedUDFs.pFirst;m;m=m->Item.pNext){
+                if(!m->udf)continue;
+                if(m->udf->HasInstances){ laWriteProp(m->udf,msp->Path->Ptr); m->udf->HasInstances=0; }
+            }
+            if((ReturnIfAnyMod||ReturnIfAnyEmpty)&&result)return result;
+            la_FreePropStepCache(PP.Go);
+        }
+    }
+    return result;
+}
+
+void la_ReadUDFToMemory(laUDF *udf){
+    if (udf->FileContent)
+        return;
+
+    fseek(udf->DiskFile, 0, SEEK_END);
+    u64bit SeekEnd = ftell(udf->DiskFile);
+    fseek(udf->DiskFile, 0, SEEK_SET);
+
+    udf->FileContent = calloc(1, SeekEnd);
+
+    fread(udf->FileContent, SeekEnd, 1, udf->DiskFile);
+
+    udf->Seek = 0;
+}
+void la_ReadOwnHyperItems(laUDF *udf, laUDFRegistry* r){
+    int Count, i;
+    laUDFOwnHyperItem *ohi;
+    Count = la_ReadLong(udf);
+    int Seek;
+    char name[256]; laUID uid;
+    for (i = 0; i < Count; i++){
+        la_ReadString(udf, uid.String);
+        la_ReadString(udf, name);
+        Seek=la_ReadPointer(udf);
+        laPropContainer* pc = la_ContainerLookup(name);
+        if(!laFindHyperItem(pc, uid.String)){
+            ohi = memAcquireSimple(sizeof(laUDFOwnHyperItem));
+            if(pc){ lstAppendItem(&pc->ResourceRegistry, ohi); }
+            ohi->Registry = r;
+            ohi->Seek = Seek;
+            strcpy(ohi->NUID.String, uid.String);
+            logPrint("Found Resource: %s | %s\n",ohi->NUID.String,name);
+        } else {logPrint("Duplicated Resource: %s | %s\n",uid.String,name);}
+    }
+}
+int la_WriteHyperRecords(laUDF *udf){
+    int i = 0;
+    u64bit CountSeek = la_Tell(udf);
+    u64bit EndSeek;
+    laUDFHyperRecordItem *hri;
+    laMemNodeHyper* h;
+    la_WriteLong(udf, 0);
+    while (hri = lstPopItem(&udf->HyperRecords)){
+        h=memGetHead(hri->HyperUserMem, 0);
+        la_WriteString(udf, h->NUID.String);
+        if(hri->pc) la_WriteString(udf, hri->pc->Identifier); else la_WriteString(udf, "");
+        la_WritePointer(udf, hri->Seek);
+        i++; memFree(hri);
+    }
+    EndSeek = la_Tell(udf);
+    la_Seek(udf, CountSeek);
+    la_WriteLong(udf, i);
+    la_Seek(udf, EndSeek);
+
+    return i;
+}
+
+laUDF *laOpenUDF(char *FileName, int ReadToMemory, laUDFRegistry* ReadRegistryRef, laManagedUDF** UseManaged){
+    char Identifier[9] = {0};
+    u64bit SeekRef;
+    laUDF *udf;
+    u64bit extensions;
+    char FilePath[1024]={0};
+
+    if(UseManaged){
+        laManagedUDF* m=la_EnsureManagedUDF(FileName, 0);
+        if(!m->udf) m->udf=memAcquire(sizeof(laUDF));
+        udf=m->udf; udf->Managed=1;
+        *UseManaged=m;
+    }else{ udf=memAcquire(sizeof(laUDF)); }
+
+    strSafeSet(&udf->FileName, FileName);
+
+    udf->DiskFile = fopen(udf->FileName->Ptr, "rb");
+    if (!udf->DiskFile) return 0;
+
+    if(ReadToMemory){ la_ReadUDFToMemory(udf); fclose(udf->DiskFile); udf->DiskFile = 0; }
+
+    la_ReadBuffer(udf, sizeof(LA_UDF_IDENTIFIER) - 1, Identifier);
+    if (!strSame(Identifier, LA_UDF_IDENTIFIER)){ laCloseUDF(udf); return 0; }
+
+    extensions = la_ReadPointer(udf);
+
+    udf->TotalRefs = la_ReadLong(udf);   //total refs
+    udf->NumSegmets = la_ReadShort(udf); //num segments
+    la_ReadLong(udf);                    //seek mark
+    SeekRef = la_ReadPointer(udf);
+    la_Seek(udf, SeekRef);
+
+    if(ReadRegistryRef){
+        la_ReadOwnHyperItems(udf, ReadRegistryRef);
+    }
+
+    la_Seek(udf, 0);
+
+    udf->Opened = 1;
+
+    return udf;
+}
+void laCloseUDF(laUDF *udf){
+    laUDFOwnHyperItem *ohi;
+    laUDFHyperRecordItem *hri;
+    laUDFPropSegment *ps;
+
+    if (udf->DiskFile){ fclose(udf->DiskFile); udf->DiskFile=0; };
+
+    while (lstPopPointer(&udf->OwnHyperItems));
+    while (lstPopPointer(&udf->HyperRecords));
+
+    if(udf->CurrentH2Instance){ logPrint("[WARN] udf->CurrentH2Instance!=0 after UDF packing.\n"); udf->CurrentH2Instance=0; }
+
+    udf->NumSegmets=0;
+
+    la_ClearHyper2Instances(udf);
+
+    if(udf->FileContent) FreeMem(udf->FileContent);
+
+    if(!udf->Managed){ strSafeDestroy(&udf->FileName); memFree(udf); }
+}
+
+laUDFOwnHyperItem* laFindHyperItem(laPropContainer* pc, char* uid){
+    if(!pc) return 0;
+    for(laUDFOwnHyperItem* ohi=pc->ResourceRegistry.pFirst;ohi;ohi=ohi->Item.pNext){
+        if(!strcmp(uid, ohi->NUID.String)) return ohi;
+    }
+    return 0;
+}
+laUDFRegistry* laFindUDFRegistry(char* Path){
+    for(laUDFRegistry* r=MAIN.ResourceRegistries.pFirst;r;r=r->Item.pNext){
+        if(r->Path && !strcmp(Path, r->Path->Ptr)) return r;
+    }
+    return 0;
+}
+laUDFRegistry* laCreateUDFRegistry(char* Path){
+    if(!Path) return 0;
+    laUDFRegistry* r = memAcquire(sizeof(laUDFRegistry));
+    strSafeSet(&r->Path, Path);
+    lstAppendItem(&MAIN.ResourceRegistries, r);
+    return r;
+}
+
+void laClearUDFRegistries(){
+    laUDFOwnHyperItem* ohi; laUDFRegistry* r;
+    for(laPropContainer* pc=MAIN.PropContainers.pFirst;pc;pc=pc->Item.pNext){
+        while(ohi=lstPopItem(&pc->ResourceRegistry)) memFree(ohi);
+    }
+    while(r=lstPopItem(&MAIN.ResourceRegistries)){
+        strSafeDestroy(&r->Path); memFree(r);
+    }
+}
+void laRefreshUDFRegistries(){
+    laClearUDFRegistries();
+    char LookupM[1024],Final[1024];
+    for(laResourceFolder* rf = MAIN.ResourceFolders.pFirst;rf;rf=rf->Item.pNext){
+        if(!rf->Path) continue;
+        realpath(rf->Path->Ptr, LookupM);
+        int len=strlen(LookupM);
+        if (LookupM[len - 1] != '/') strcat(LookupM, "/");
+
+        struct dirent **NameList;
+        int NumFiles=scandir(LookupM,&NameList,0,alphasort);
+
+        for(int i=0;i<NumFiles;i++){
+            struct dirent* d = NameList[i]; int dlen;
+            if((dlen=strlen(d->d_name))<=4 || strcmp(&d->d_name[dlen-4], ".udf")){continue;}
+            struct stat s;
+            sprintf(Final, "%s%s",LookupM,d->d_name);
+            stat(Final, &s);
+            if (!S_ISDIR(s.st_mode)){
+                if(!laFindUDFRegistry(Final)){
+                    laUDFRegistry* r = laCreateUDFRegistry(Final);
+                    laUDF* udf = laOpenUDF(Final, 0, r, 0);
+                    if(udf) laCloseUDF(udf);
+                }
+            }
+        }        
+        for (int i=0;i<NumFiles;i++){ free(NameList[i]); }
+    }
+}
+
+void la_FindAndExtractUDFContentNode(laUDF *udf, laManagedUDF* mUDF, int Mode, laUDFContentNode *ContentNode){
+    laUDFContentNode *ucn, *ucn2;
+    laUDFContentInstance *uci;
+    laDBInst *dbi = 0;
+
+    if (!udf || !ContentNode) return 0;
+
+    ucn = ContentNode;
+    la_StepPropPack(&ucn->PP);
+
+    la_Seek(udf, ucn->FileSeek);
+    dbi = ucn->PP.EndInstance; //la_GetWriteDBInst(ucn->PP.EndInstance);
+    la_ExtractProp(udf, mUDF, &ucn->PP, dbi, Mode, 0);
+    
+}
+int laExtractUDFContent(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *ContentNodes){
+    laUDFContentNode *ucn;
+    laUDFContentInstance *uci;
+    if (!udf || !ContentNodes) return 0;
+
+    for (ucn = ContentNodes->pFirst; ucn; ucn = ucn->Item.pNext){
+        la_FindAndExtractUDFContentNode(udf, mUDF, Mode, ucn);
+    }
+
+    la_RematchPointers(Mode);
+
+    return 1;
+}
+
+void laStopManageUDF(laManagedUDF* m){
+    if(!m) return;
+    lstRemoveItem(&MAIN.ManagedUDFs,m);
+    if(m->udf) { m->udf->Managed=0; laCloseUDF(m->udf); };
+    strSafeDestroy(&m->BaseName);
+    memFree(m);
+}
+void laClearManagedUDF(){
+    laManagedUDF* m;
+    while(m=MAIN.ManagedUDFs.pFirst){ laStopManageUDF(m); }
+}
+
+void laSaveManagedUDF(){
+    laRegisterModifications(0,0,0,1);
+    for(laManagedUDF* m=MAIN.ManagedUDFs.pFirst;m;m=m->Item.pNext){
+        if(!m->udf) continue;
+        if(m->udf->PropsToOperate.pFirst){ laPackUDF(m->udf, 1); }
+        laCloseUDF(m->udf);// just in case
+    }
+}
+
+void laPropagateUDF(laPropContainer* pc, void* inst, int force){
+    if(!pc->UDFPropagate) return;
+    void* udf=laget_InstanceActiveUDF(inst); if(udf==MAIN.DummyManageUDF) return;
+    pc->UDFPropagate(inst, udf, force);
+}
+
+//==========================================================================[Manifest]
+
+void laAddResourceFolder(char* Path){
+    laResourceFolder* rf=memAcquire(sizeof(laResourceFolder));
+    if(Path) strSafeSet(&rf->Path, Path);
+    lstAppendItem(&MAIN.ResourceFolders, rf);
+}
+void laRemoveResourceFolder(laResourceFolder* rf){
+    strSafeDestroy(&rf->Path);
+    lstRemoveItem(&MAIN.ResourceFolders, rf);
+    memFree(rf);
+}
+
+void la_ClearUDFRegistryAndFolders(){
+    laResourceFolder* rf; while(rf=MAIN.ResourceFolders.pFirst){ laRemoveResourceFolder(rf); }
+    laClearUDFRegistries();
+}
+
+//==========================================================================[undo]
+
+void laPushDifferences(char* Description, u64bit hint){
+    laDiff* d=memAcquire(sizeof(laDiff));
+    lstAppendItem(&MAIN.Differences, d);
+    if(MAIN.HeadDifference && Description) strSafeSet(&MAIN.HeadDifference->Description,Description);
+    d->Hint=hint;
+    MAIN.HeadDifference=d;
+}
+
+void la_FreeInstance(void* inst, laPropContainer* pc, int no_free);
+void la_FreeDBInst(laDBInst* dbi);
+void la_FreeDBProp(laDBProp* dbp){
+    if(dbp->p->PropertyType==LA_PROP_SUB){
+        if((((laSubProp*)dbp->p)->ListHandleOffset||dbp->p->UDFNoCreate||dbp->p->UDFIsSingle)){
+            laDBSubProp* dsp=dbp; laDBInst* si;
+            while(si=lstPopItem(&dsp->Instances)){ la_FreeDBInst(si); }
+        } // prevent freeing the data;
+    }elif(dbp->p->PropertyType==LA_PROP_STRING && ((laStringProp*)dbp->p)->IsSafeString){
+        strSafeSet(&dbp->Data,0);
+    }else{
+        printf("free %s\n",dbp->p->Identifier);
+        memFree(dbp->Data);
+    }
+    memFree(dbp);
+}
+void la_FreeDBInst(laDBInst* dbi){
+    laListHandle* l=hsh65536DoHashLongPtr(MAIN.DBInstLink,dbi->OriginalInstance); lstRemoveItem(l, &dbi->Item2);
+    laDBProp* dbp; while(dbp=lstPopItem(&dbi->Props)){ la_FreeDBProp(dbp); }
+    if(dbi->OriginalInstance) la_FreeInstance(dbi->OriginalInstance, dbi->pc, 0);
+    memFree(dbi);
+}
+void la_FreeDiffCommand(laDiffCommand* dc, laDiff* d){
+    if(dc->p->PropertyType==LA_PROP_SUB && (((laSubProp*)dc->p)->ListHandleOffset||dc->p->UDFNoCreate||dc->p->UDFIsSingle)){
+        laDiffCommandInst* dci; laDiffCommandSub* dcs=dc;
+        while(dci=lstPopItem(&dcs->AddedInst)){ la_FreeDBInst(dci->DBInst); memFree(dci); }
+        while(dci=lstPopItem(&dcs->MovedInst)){ memFree(dci); }
+        while(dci=lstPopItem(&dcs->RemovedInst)){ dci->DBInst->DeletedDiff = 0; memFree(dci); }
+    }elif(dc->p->PropertyType==LA_PROP_STRING && ((laStringProp*)dc->p)->IsSafeString){
+        strSafeSet(&dc->Data,0);
+    }
+    memFree(dc);
+}
+void la_FreeDifference(laDiff* d){
+    laDiffCommand* dc; laDiffExtraTouched* det;
+    while(dc=lstPopItem(&d->Commands)){ la_FreeDiffCommand(dc,d); }
+    while(det=lstPopItem(&d->ExtraTouched)){ memFree(det); }
+    if(d->Description&&d->Description->Ptr){printf("%s\n",d->Description->Ptr);}
+    strSafeDestroy(&d->Description);
+}
+void la_FreeNewerDifferences(){
+    laDiff* PrevD;
+    if(MAIN.HeadDifference==MAIN.Differences.pLast) return;
+    for(laDiff* d=MAIN.Differences.pLast;d;d=PrevD){
+        PrevD=d->Item.pPrev;
+        lstRemoveItem(&MAIN.Differences,d);
+        la_FreeDifference(d);
+        if(MAIN.HeadDifference==d){ MAIN.HeadDifference=PrevD; laPushDifferences("desc",0); break; }
+    }
+}
+void la_FreeAllDifferences(){
+    MAIN.HeadDifference=MAIN.Differences.pFirst;
+    la_FreeNewerDifferences();
+}
+void la_NoLongerRecordUndo(){
+    la_FreeAllDifferences();
+    laDBProp*dbp; while(dbp=lstPopItem(&MAIN.RootDBInst.Props)){ la_FreeDBProp(dbp); }
+    laDBRecordedProp* p; while(p=lstPopItem(&MAIN.DBRecordedProps)){ strSafeDestroy(&p->OriginalPath); memFree(p); }
+    hshFree(&MAIN.DBInstLink);
+}
+
+void la_RelinkDBInst(laDBInst* dbi, void* New_OriginalInstance){
+    if(dbi->OriginalInstance){
+        laListHandle* l=hsh65536DoHashLongPtr(MAIN.DBInstLink,dbi->OriginalInstance); lstRemoveItem(l, &dbi->Item2);
+    }
+    dbi->OriginalInstance = New_OriginalInstance;
+    laListHandle* l=hsh65536DoHashLongPtr(MAIN.DBInstLink,dbi->OriginalInstance); lstPushItem(l, &dbi->Item2);
+}
+laDBInst* laAddDBInst(laDBProp* parent, void* inst, laPropContainer* pc, laDiff* Begin){
+    laDBInst* dbi=memAcquire(sizeof(laDBInst)); if(!Begin) Begin=MAIN.HeadDifference;
+    dbi->pc=pc; dbi->CreatedDiff = Begin;
+    if(parent){ lstAppendItem(&((laDBSubProp*)parent)->Instances, dbi); }
+    la_RelinkDBInst(dbi, inst);
+    return dbi;
+}
+laDBProp* laAddDBProp(laDBInst* dbi, laProp* p, void* data){
+    int size=sizeof(laDBProp);
+    if(p->PropertyType==LA_PROP_SUB && (!p->UDFIsRefer)){size=sizeof(laDBSubProp);}
+    elif(p->PropertyType==LA_PROP_RAW){size=sizeof(laDBRawProp);}
+    laDBProp* dbp=memAcquire(size);
+    dbp->p=p; dbp->Data=data;
+    lstAppendItem(&dbi->Props, dbp);
+    return dbp;
+}
+void laAddDBPReferAcquire(laDBProp* dbp){
+    if(!dbp->Data) return; if(!lstHasPointer(&MAIN.DBInstPendingAcquireDBP, dbp)) lstAppendPointer(&MAIN.DBInstPendingAcquireDBP, dbp);
+}
+void laAddDiffCMDReferAcquire(laDiffCommand* ds){
+    if(!ds->Data) return; if(!lstHasPointer(&MAIN.DBInstPendingAcquireDiffCMD, ds)) lstAppendPointer(&MAIN.DBInstPendingAcquireDiffCMD, ds);
+}
+
+laDiffCommand* la_GiveDiffCommand(laDiff* diff, laDBInst* Instance, laProp* p, void* Data){
+    for(laDiffCommand* dc=diff->Commands.pFirst;dc;dc=dc->Item.pNext){
+        if(dc->Instance == Instance && dc->p == p) return dc;
+    }
+    int size=sizeof(laDiffCommand);
+    if(p->PropertyType==LA_PROP_SUB && (!(p->UDFIsRefer||p->UDFIsSingle||p->UDFNoCreate))){size=sizeof(laDiffCommandSub);}
+    elif(p->PropertyType==LA_PROP_RAW){size=sizeof(laDiffCommandRaw);}
+    laDiffCommand* dc = memAcquire(size);
+    dc->Instance=Instance; dc->p=p; dc->Data = Data;
+    lstAppendItem(&diff->Commands,dc);
+    return dc;
+}
+void la_GiveExtraTouched(laDiff* diff, laDBInst* dbi){
+    if(!dbi->pc->UndoTouched) return;
+    laDiffExtraTouched* det=memAcquire(sizeof(laDiffExtraTouched));
+    det->dbi=dbi; lstAppendItem(&diff->ExtraTouched,det);
+}
+
+int la_AddIntDBProp(laDBInst* dbi, laDBProp* dbp, laDiff* diff, laPropPack *pp){
+    laProp *p = pp->LastPs->p; int *Data; int len = laGetArrayLength(pp); int ret=0;
+    Data= memAcquireSimple(sizeof(int)*len);
+    laGetIntArray(pp, Data); if(diff&&dbp){
+        if(memcmp(dbp->Data, Data, sizeof(int)*len)){ la_GiveDiffCommand(diff, dbi, p, dbp->Data); dbp->Data=Data; ret=1; } else memFree(Data);
+    }
+    else laAddDBProp(dbi, p, Data);
+    return ret;
+}
+int la_AddFloatDBProp(laDBInst* dbi, laDBProp* dbp, laDiff* diff, laPropPack *pp){
+    laProp *p = pp->LastPs->p; real *Data; int len = laGetArrayLength(pp); int ret=0;
+    Data= memAcquireSimple(sizeof(real)*len);
+    laGetFloatArray(pp, Data); if(diff&&dbp){
+        if(memcmp(dbp->Data, Data, sizeof(real)*len)){ la_GiveDiffCommand(diff, dbi, p, dbp->Data); dbp->Data=Data; ret=1; } else memFree(Data);
+    }
+    else laAddDBProp(dbi, p, Data);
+    return ret;
+}
+int la_AddStringDBProp(laDBInst* dbi, laDBProp* dbp, laDiff* diff, laPropPack *pp){
+    laProp *p = pp->LastPs->p; char _buf[LA_RAW_CSTR_MAX_LEN]={0}; char* buf=_buf; int ret=0;
+    laGetString(pp, _buf, &buf); if(diff&&dbp){
+        if((!dbp->Data&&buf[0]) || (buf[0] && strcmp(buf, ((laSafeString*)dbp->Data)->Ptr)) || (!buf[0]&&dbp->Data)){
+            laDiffCommand* dc=la_GiveDiffCommand(diff, dbi, p, dbp->Data); dbp->Data=0; strSafeSet(&dbp->Data, buf); ret=1; }
+    }else{
+        laDBProp* dbp=laAddDBProp(dbi, p, 0); strSafeSet(&dbp->Data, buf);
+    }
+    return ret;
+}
+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); 
+    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);
+    return ret;
+}
+int la_AddRawDBProp(laDBInst* dbi, laDBRawProp* dbp, laDiff* diff, laPropPack *pp){
+    laProp *p = pp->LastPs->p; int *Data; int s=0; int ret=0; int IsCopy=0;
+    Data=laGetRaw(pp,&s,&IsCopy); if(diff&&dbp){
+        if(dbp->DataSize!=s || (!dbp->Data&&Data) || (!Data&&dbp->Data) || (dbp->Data&&Data&&memcmp(dbp->Data, Data, s))){
+            printf("s%d %x %d \n",s,Data,dbp->DataSize);
+            void* NewData=s?calloc(1,s):0;
+            if(s)memcpy(NewData, Data, s);
+            laDiffCommandRaw* dcr=la_GiveDiffCommand(diff, dbi, p, dbp->Data);
+            dcr->DataSize=dbp->DataSize; dbp->Data=NewData; dbp->DataSize=s; ret=1;
+        }
+    }
+    else{
+        void* NewData=s?calloc(1,s):0; if(s) memcpy(NewData, Data, s);
+        laDBRawProp* dbp=laAddDBProp(dbi, p, NewData); dbp->DataSize=s;
+    }
+    if(IsCopy){ free(Data); }
+    return ret;
+}
+
+laDiffCommandInst* la_NewDiffCommandInst(laDBInst* DBInst, laDBInst* Prev, laDBInst* Next){
+    laDiffCommandInst* dci=memAcquire(sizeof(laDiffCommandInst));
+    dci->DBInst = DBInst; dci->OriginalPrev = Prev; dci->OriginalNext = Next;
+    dci->BeforePrev = DBInst->Item.pPrev; dci->BeforeNext = DBInst->Item.pNext;
+}
+laDBInst* la_GetDiffDBInst(laListHandle* NewAdded, laListHandle* Master, void* instance){
+    if(!instance) return 0;
+    for(laDiffTemp* dt=NewAdded->pFirst;dt;dt=dt->Item.pNext){
+        if(((laDBInst*)dt->p)->OriginalInstance == instance) return dt->p;
+    }
+    for(laDBInst* dbi=Master->pFirst;dbi;dbi=dbi->Item.pNext){
+        if(dbi->OriginalInstance==instance) return dbi;
+    }
+    return 0;
+}
+
+int la_GenerateListDifferences(laDBInst* dbi, laDBSubProp* dbp, laPropPack* pp, laDiff* diff){
+    laProp *p = pp->LastPs->p, *subp = 0;
+    laPropIterator pi={0};
+    void* inst; int any=0;
+    laListHandle New={0}, NewAdded={0}, NewDeleted={0}, NewMoved={0};
+    
+    inst = laGetInstance(p, pp->LastPs->UseInstance, &pi);
+    pp->EndInstance = inst;
+    while (inst){
+        lstAppendPointer(&New, inst);
+        inst = laGetNextInstance(p, inst, &pi);
+        pp->EndInstance = inst;
+    }
+
+    for(laDBInst* dbi=dbp->Instances.pFirst;dbi;dbi=dbi->Item.pNext){
+        void* OldPrev=dbi->Item.pPrev?((laDBInst*)dbi->Item.pPrev)->OriginalInstance:0;
+        void* OldNext=dbi->Item.pNext?((laDBInst*)dbi->Item.pNext)->OriginalInstance:0;
+        int found=0; for(laListItemPointer* lip=New.pFirst;lip;lip=lip->pNext){
+            void* NewPrev=lip->pPrev?((laListItemPointer*)lip->pPrev)->p:0;
+            void* NewNext=lip->pNext?((laListItemPointer*)lip->pNext)->p:0;
+            if(lip->p == dbi->OriginalInstance){
+                found=1;
+                if(OldPrev==NewPrev && OldNext==NewNext){break;}
+                else{ laDiffTemp* dt=lstAppendPointerSized(&NewMoved, dbi, sizeof(laDiffTemp));
+                    dt->tPrev=dbi->Item.pPrev; dt->tNext=dbi->Item.pNext; dt->nPrev=NewPrev; dt->nNext=NewNext;break;}
+            }
+        }
+        if(!found){
+            laDiffTemp* dt=lstAppendPointerSized(&NewDeleted, dbi, sizeof(laDiffTemp));dt->tPrev=dbi->Item.pPrev;dt->tNext=dbi->Item.pNext; any++;
+        }
+    }
+    for(laListItemPointer* lip=New.pFirst;lip;lip=lip->pNext){
+        int found=0; for(laDBInst* dbi=dbp->Instances.pFirst;dbi;dbi=dbi->Item.pNext){
+            if(lip->p == dbi->OriginalInstance){ found=1; }
+        }
+        if(!found){ any++;
+            laDiffTemp* dt=lstAppendPointerSized(&NewAdded, lip->p, sizeof(laDiffTemp));
+            void* NewPrev=lip->pPrev?((laListItemPointer*)lip->pPrev)->p:0;
+            void* NewNext=lip->pNext?((laListItemPointer*)lip->pNext)->p:0;
+            dt->tPrev=NewPrev; dt->tNext=NewNext;
+            laPropContainer* spc=p->SubProp; if(((laSubProp*)p)->GetType){spc=((laSubProp*)p)->GetType(lip->p);}
+            laDBInst* newdbi=laAddDBInst(0, lip->p, spc, diff); dt->p=newdbi;
+            for (subp = spc->Props.pFirst; subp; subp = subp->Item.pNext){
+                if (subp->UDFIgnore) continue;
+                if (subp->PropertyType == LA_PROP_OPERATOR) continue;
+                laPropStep SubPS = {0}; laPropPack SubPP = {0}; laPropIterator pi={0};
+                SubPP.RawThis = pp; SubPS.p = subp; SubPS.UseInstance = lip->p; SubPP.LastPs=&SubPS;
+                any+=laIterateDB(newdbi, &SubPP, 0, 0);
+            }
+        }
+    }
+
+    for(laDiffTemp* lip=NewAdded.pFirst;lip;lip=lip->Item.pNext){
+        laDBInst* newdbi=lip->p;
+        lip->tPrev = la_GetDiffDBInst(&NewAdded, &dbp->Instances, lip->tPrev);
+        lip->tNext = la_GetDiffDBInst(&NewAdded, &dbp->Instances, lip->tNext);
+    }
+    for(laDiffTemp* lip=NewMoved.pFirst;lip;lip=lip->Item.pNext){
+        laDBInst* newdbi=lip->p;
+        lip->tPrev = la_GetDiffDBInst(&NewAdded, &dbp->Instances, lip->nPrev);
+        lip->tNext = la_GetDiffDBInst(&NewAdded, &dbp->Instances, lip->nNext);
+    }
+
+    laDiffCommandSub* dc=(NewAdded.pFirst||NewDeleted.pFirst||NewMoved.pFirst)?la_GiveDiffCommand(diff, dbi, p, 0):0;
+    for(laDiffTemp* lip=NewAdded.pFirst;lip;lip=lip->Item.pNext){
+        lstAppendItem(&dc->AddedInst, la_NewDiffCommandInst(lip->p, 0, 0));
+        laDBInst* newdbi=lip->p;
+        newdbi->Item.pPrev = lip->tPrev; newdbi->Item.pNext = lip->tNext;
+        if(!newdbi->Item.pPrev){dbp->Instances.pFirst=newdbi;}
+        if(!newdbi->Item.pNext){dbp->Instances.pLast=newdbi;}
+    }
+    for(laDiffTemp* lip=NewMoved.pFirst;lip;lip=lip->Item.pNext){
+        laDBInst* dbi=lip->p; lstAppendItem(&dc->MovedInst, la_NewDiffCommandInst(dbi, lip->tPrev, lip->tNext));
+        laDBInst* newdbi=lip->p;
+        newdbi->Item.pPrev = lip->tPrev; newdbi->Item.pNext = lip->tNext;
+        if(!dbi->Item.pPrev){dbp->Instances.pFirst=dbi;}
+        if(!dbi->Item.pNext){dbp->Instances.pLast=dbi;}
+    }
+    
+    for(laDiffTemp* lip=NewDeleted.pFirst;lip;lip=lip->Item.pNext){
+        laDBInst* dbi=lip->p; lstAppendItem(&dc->RemovedInst, la_NewDiffCommandInst(dbi, lip->tPrev, lip->tNext));printf("deleted %x %x\n", dbi, dbi->OriginalInstance);
+        //if(!dbi->Item.pPrev){dbp->Instances.pFirst=dbi->Item.pNext;}
+        //if(!dbi->Item.pNext){dbp->Instances.pLast=dbi->Item.pPrev;}
+        dbi->Item.pPrev=dbi->Item.pNext=0; //lstRemoveItem(&dbp->Instances, dbi);
+        laPropStep SubPS = {0}; laPropPack SubPP = {0}; laPropIterator pi={0}; laDBProp* dpi=0; SubPP.LastPs = &SubPS;
+        laPropContainer* spc=p->SubProp; if(((laSubProp*)p)->GetType){spc=((laSubProp*)p)->GetType(inst);}
+        dpi=dbi->Props.pFirst;
+        for (subp = spc->Props.pFirst; subp; subp = subp->Item.pNext){
+            if (subp->PropertyType == LA_PROP_OPERATOR) continue;
+            if(subp->UDFIgnore){ continue; }
+
+            if((!dpi)||dpi->p!=subp) printf("Prop doesn't match\n");
+
+            SubPP.RawThis = pp; SubPS.p = subp; SubPS.UseInstance = inst;
+            int thisany=laIterateDB(dbi, &SubPP, diff, dpi);
+            
+            dpi=dpi->Item.pNext;
+            if(thisany){ any+=thisany; la_GiveExtraTouched(diff,dbi); }
+        }
+        inst = laGetNextInstance(p, inst, &pi);
+        pp->EndInstance = inst;
+        if(diff){ dbi=dbi->Item.pNext; }
+    }
+
+    //printf("%x ~ %x\n", dbp->Instances.pFirst, dbp->Instances.pLast);
+    //laListItem* item = laGetInstance(p, pp->LastPs->UseInstance, &pi);
+    //while (item){
+    //    printf("    %x [%x] %x\n",item->pPrev, item, item->pNext);
+    //    item = laGetNextInstance(p, item, &pi);
+    //}
+    return any;
+}
+
+int laIterateDB(laDBInst* parent, laPropPack* pp, laDiff* diff, laDBProp* dp){
+    laProp *p = pp->LastPs->p, *subp = 0;
+    laPropStep SubPS = {0}; laPropPack SubPP = {0}; laPropIterator pi={0};
+    laDBProp* dbp; laDBSubProp* dsp; laDBInst* dbi; laDBProp* dpi=0;
+    void *inst = 0;
+    SubPP.LastPs = &SubPS;
+    int any=0;
+
+    switch (p->PropertyType){
+    case LA_PROP_SUB:
+        if (p->UDFIsRefer){ if(!parent) return;
+            inst = laGetActiveInstanceStrict(p, pp->LastPs->UseInstance);
+            if(diff){
+                if(inst!=dp->Data) la_GiveDiffCommand(diff, parent, p, dp->Data); dp->Data=inst; any++;
+            }else{
+                laDBProp* rdbp=laAddDBProp(parent, p, inst);
+            }
+        }else{
+            if (!p->SubProp) p->SubProp = la_ContainerLookup(((laSubProp *)p)->TargetID);
+            if(diff){ any+=la_GenerateListDifferences(parent, dp, pp, diff); dsp=dp; dbi=dsp->Instances.pFirst; dbp=dsp; }
+            else{ dbp=laAddDBProp(parent, p, laGetActiveInstance(p, pp->LastPs->UseInstance, &pi)); }
+
+            inst = laGetInstance(p, pp->LastPs->UseInstance, &pi);
+            pp->EndInstance = inst;
+            while (inst){ //printf("work  %x\n",inst);
+                laPropContainer* spc=p->SubProp; if(((laSubProp*)p)->GetType){spc=((laSubProp*)p)->GetType(inst);}
+                if(diff){
+                    if(dbi->OriginalInstance != inst){ 
+                        printf("dbi/inst doesn't match.\n"); }
+                    dpi=dbi->Props.pFirst;
+                }else{ dbi = laAddDBInst(dbp, inst, spc, 0); }
+                
+                for (subp = spc->Props.pFirst; subp; subp = subp->Item.pNext){
+                    if (subp->PropertyType == LA_PROP_OPERATOR) continue;
+                    if(subp->UDFIgnore){ continue; }
+
+                    if(diff && ((!dpi)||dpi->p!=subp)){
+                         printf("Prop doesn't match\n");}
+
+                    SubPP.RawThis = pp; SubPS.p = subp; SubPS.UseInstance = inst;
+                    int thisany=laIterateDB(dbi, &SubPP, diff, dpi);
+                    
+                    if(diff && dpi){ dpi=dpi->Item.pNext;
+                        if(thisany){ any+=thisany;
+                         la_GiveExtraTouched(diff,dbi); }
+                    }
+                }
+                inst = laGetNextInstance(p, inst, &pi);
+                pp->EndInstance = inst;
+                if(diff){ dbi=dbi->Item.pNext; }
+            }
+        }
+        break;
+    case LA_PROP_INT: case LA_PROP_ARRAY | LA_PROP_INT:
+        any+=la_AddIntDBProp(parent, dp, diff, pp); break;
+    case LA_PROP_FLOAT: case LA_PROP_ARRAY | LA_PROP_FLOAT:
+        any+=la_AddFloatDBProp(parent, dp, diff, pp); break;
+    case LA_PROP_STRING:
+        any+=la_AddStringDBProp(parent, dp, diff, pp); break;
+    case LA_PROP_ENUM:  case LA_PROP_ARRAY | LA_PROP_ENUM:
+        any+=la_AddEnumDBProp(parent, dp, diff, pp); break;
+    case LA_PROP_RAW:
+        any+=la_AddRawDBProp(parent,dp,diff,pp); break;
+    default: break;
+    }
+    return any;
+}
+
+void la_RestoreIntDBProp(laDBProp* dbp, laDiffCommand* dc){
+    laPropPack pp={0}; laPropStep ps={0}; ps.p=dc->p; pp.LastPs=&ps; ps.UseInstance=dc->Instance->OriginalInstance;
+    int *Data; Data=dc->Data; dc->Data=dbp->Data; dbp->Data=Data;
+    laSetIntArrayAllArray(&pp, dbp->Data);
+}
+void la_RestoreFloatDBProp(laDBProp* dbp, laDiffCommand* dc){
+    laPropPack pp={0}; laPropStep ps={0}; ps.p=dc->p; pp.LastPs=&ps; ps.UseInstance=dc->Instance->OriginalInstance;
+    int *Data; Data=dc->Data; dc->Data=dbp->Data; dbp->Data=Data;
+    laSetFloatArrayAllArray(&pp, dbp->Data);
+}
+void la_RestoreStringDBProp(laDBProp* dbp, laDiffCommand* dc){
+    laPropPack pp={0}; laPropStep ps={0}; ps.p=dc->p; pp.LastPs=&ps; ps.UseInstance=dc->Instance->OriginalInstance;
+    int *Data; Data=dc->Data; dc->Data=dbp->Data; dbp->Data=Data;
+    laSetString(&pp, dbp->Data?((laSafeString*)dbp->Data)->Ptr:0);
+}
+void la_RestoreEnumDBProp(laDBProp* dbp, laDiffCommand* dc){
+    laPropPack pp={0}; laPropStep ps={0}; ps.p=dc->p; pp.LastPs=&ps; ps.UseInstance=dc->Instance->OriginalInstance;
+    int *Data; Data=dc->Data; dc->Data=dbp->Data; dbp->Data=Data;
+    laSetEnumArrayAllArray(&pp, dbp->Data);
+}
+void la_RestoreRawDBProp(laDBRawProp* dbp, laDiffCommandRaw* dc){
+    laPropPack pp={0}; laPropStep ps={0}; ps.p=dc->p; pp.LastPs=&ps; ps.UseInstance=dc->Instance->OriginalInstance;
+    int *Data; Data=dc->Data; dc->Data=dbp->Data; dbp->Data=Data; LA_SWAP(int, dc->DataSize, dbp->DataSize);
+    laSetRaw(&pp,dbp->Data,dbp->DataSize);
+}
+
+void la_AddUndoPostNode(laDBInst* dbi){
+    if(!dbi->pc->UndoTouched) return;
+    for(laDiffPost* dp=MAIN.DiffTouched.pLast;dp;dp=dp->Item.pPrev){ if(dp->instance==dbi->OriginalInstance&&dp->Touched==dbi->pc->UndoTouched) return; }
+    laDiffPost* dp=lstAppendPointerSized(&MAIN.DiffTouched, dbi->OriginalInstance, sizeof(laDiffPost));
+    dp->Touched=dbi->pc->UndoTouched;
+}
+
+void la_ExecUndoPtrSync(laDiff* d){
+    int hint=d->Hint; laDiffPtrSync* dps; laDiffPost* dp; laDBInstPendingRelink* dpr;
+
+    while(dp=lstPopItem(&MAIN.DiffTouched)){
+        dp->Touched(dp->instance, hint);
+        memFree(dp);
+    }
+    for(laDiffExtraTouched*det=d->ExtraTouched.pFirst;det;det=det->Item.pNext){
+        det->dbi->pc->UndoTouched(det->dbi->OriginalInstance, hint);
+    }
+}
+void la_FreeInstance(void* inst, laPropContainer* pc, int no_free){
+    //if(p->PropertyType!=LA_PROP_SUB) return;
+    //if(!p->SubProp || ((laSubProp*)p)->TargetID) p->SubProp=la_ContainerLookup(((laSubProp*)p)->TargetID);
+    //laPropContainer* pc=p->SubProp; if(((laSubProp*)p)->GetType) pc=((laSubProp*)p)->GetType(inst);
+    if(pc->BeforeFree) pc->BeforeFree(inst);
+    laPropStep SubPS = {0}; laPropPack SubPP = {0}; laPropIterator pi={0}; SubPP.LastPs=&SubPS; 
+    for(laProp* p=pc->Props.pFirst;p;p=p->Item.pNext){
+        if(p->PropertyType==LA_PROP_STRING && ((laStringProp*)p)->IsSafeString){ SubPS.p=p; SubPS.UseInstance=inst; laSetString(&SubPP, 0); continue; }
+        if(p->PropertyType!=LA_PROP_SUB || p->UDFIsRefer) continue;
+        void* si = laGetInstance(p, SubPP.LastPs->UseInstance, &pi); SubPP.EndInstance = si; void* NextSi=0;
+        while (si){
+            NextSi = laGetNextInstance(p, si, &pi);
+            if(!p->UDFNoCreate){ laSubProp* sp=p;
+                if(!sp->ListHandleOffset){ logPrint("[WARN] prop '%s' UDFNoCreate==0 and no ListHandleOffset. Node not removed.\n", p->Identifier); }
+                else{ lstRemoveItem(inst + sp->ListHandleOffset, si); }
+            }
+            la_FreeInstance(si, p, p->UDFNoCreate);
+            si=NextSi; SubPP.EndInstance = si;
+        }
+    }
+    if(!no_free) memFree(inst);
+}
+void la_ResetInstance(void* inst, laPropContainer* pc){ memset(inst,0,pc->NodeSize); }
+
+laListHandle* la_GetOriginalListHandle(laDiffCommandSub* dcs){
+    laProp*p =dcs->Base.p;
+    if(p->PropertyType!=LA_PROP_SUB||p->UDFIsRefer||!((laSubProp*)p)->ListHandleOffset) return 0;
+    laSubProp* sp=dcs->Base.p;
+    void* addr=((char*)dcs->Base.Instance->OriginalInstance)+((laSubProp*)p)->ListHandleOffset;
+    return addr;
+}
+
+void la_UndoListDifferences(laDBSubProp* dsp, laDiffCommandSub* dcs){
+    laListHandle* ol=la_GetOriginalListHandle(dcs);
+    for(laDiffCommandInst* dci=dcs->AddedInst.pFirst;dci;dci=dci->Item.pNext){
+        if(dcs->Base.p->UDFNoCreate){ la_ResetInstance(dci->DBInst->OriginalInstance,dci->DBInst->pc); continue; }
+        dci->OriginalPrev = dci->DBInst->Item.pPrev; dci->OriginalNext = dci->DBInst->Item.pNext;
+        //if(dsp->Instances.pFirst == dci->DBInst){ dsp->Instances.pFirst=dci->DBInst->Item.pNext; ol->pFirst=dci->DBInst->Item.pNext?((laDBInst*)dci->DBInst->Item.pNext)->OriginalInstance:0; }
+        //if(dsp->Instances.pLast == dci->DBInst){ dsp->Instances.pLast=dci->DBInst->Item.pPrev; ol->pLast=dci->DBInst->Item.pPrev?((laDBInst*)dci->DBInst->Item.pPrev)->OriginalInstance:0; }
+        //dci->DBInst->Item.pPrev = dci->DBInst->Item.pNext=0;
+    }
+    for(laDiffCommandInst* dci=dcs->AddedInst.pFirst;dci;dci=dci->Item.pNext){
+        if(dcs->Base.p->UDFNoCreate){  continue; }
+        lstRemoveItem(&dsp->Instances, dci->DBInst); lstRemoveItem(ol, dci->DBInst->OriginalInstance); 
+        laListItem* li = dci->DBInst->OriginalInstance;
+    }
+    for(laDiffCommandInst* dci=dcs->RemovedInst.pFirst;dci;dci=dci->Item.pNext){ if(dcs->Base.p->UDFNoCreate) continue;
+        dci->DBInst->Item.pPrev = dci->OriginalPrev;
+        dci->DBInst->Item.pNext = dci->OriginalNext; printf("add removed %x \n", dci->DBInst->OriginalInstance);
+        void* orig = dci->DBInst->OriginalInstance;
+    }
+    for(laDiffCommandInst* dci=dcs->RemovedInst.pFirst;dci;dci=dci->Item.pNext){ if(dcs->Base.p->UDFNoCreate) continue;
+        ((laListItem*)dci->DBInst->OriginalInstance)->pPrev=dci->OriginalPrev?dci->OriginalPrev->OriginalInstance:0;
+        ((laListItem*)dci->DBInst->OriginalInstance)->pNext=dci->OriginalNext?dci->OriginalNext->OriginalInstance:0;
+        if(!dci->DBInst->Item.pPrev){ dsp->Instances.pFirst=dci->DBInst; ol->pFirst=dci->DBInst->OriginalInstance; }
+        if(!dci->DBInst->Item.pNext){ dsp->Instances.pLast=dci->DBInst; ol->pLast=dci->DBInst->OriginalInstance; }
+    }
+    for(laDiffCommandInst* dci=dcs->MovedInst.pFirst;dci;dci=dci->Item.pNext){
+        dci->DBInst->Item.pPrev = dci->BeforePrev; ((laListItem*)dci->DBInst->OriginalInstance)->pPrev=dci->BeforePrev?dci->BeforePrev->OriginalInstance:0;
+        dci->DBInst->Item.pNext = dci->BeforeNext; ((laListItem*)dci->DBInst->OriginalInstance)->pNext=dci->BeforeNext?dci->BeforeNext->OriginalInstance:0;
+        if(!dci->DBInst->Item.pPrev){ dsp->Instances.pFirst=dci->DBInst; ol->pFirst=dci->DBInst->OriginalInstance; }
+        if(!dci->DBInst->Item.pNext){ dsp->Instances.pLast=dci->DBInst; ol->pLast=dci->DBInst->OriginalInstance; }
+    }
+}
+void la_RedoListDifferences(laDBSubProp* dsp, laDiffCommandSub* dcs){
+    laListHandle* ol=la_GetOriginalListHandle(dcs);
+    for(laDiffCommandInst* dci=dcs->RemovedInst.pFirst;dci;dci=dci->Item.pNext){
+        if(dcs->Base.p->UDFNoCreate){ la_ResetInstance(dci->DBInst->OriginalInstance,dci->DBInst->pc); continue; }
+        //dci->OriginalPrev = dci->DBInst->Item.pPrev;
+        //dci->OriginalNext = dci->DBInst->Item.pNext;
+        lstRemoveItem(&dsp->Instances, dci->DBInst); lstRemoveItem(ol, dci->DBInst->OriginalInstance); 
+        laListItem* li = dci->DBInst->OriginalInstance;
+        printf("remove %x \n", dci->DBInst->OriginalInstance);
+    }
+    for(laDiffCommandInst* dci=dcs->AddedInst.pFirst;dci;dci=dci->Item.pNext){ if(dcs->Base.p->UDFNoCreate) continue;
+        dci->DBInst->Item.pPrev = dci->OriginalPrev;
+        dci->DBInst->Item.pNext = dci->OriginalNext;
+        void* orig = dci->DBInst->OriginalInstance;
+    }
+    for(laDiffCommandInst* dci=dcs->AddedInst.pFirst;dci;dci=dci->Item.pNext){ if(dcs->Base.p->UDFNoCreate) continue;
+        ((laListItem*)dci->DBInst->OriginalInstance)->pPrev=dci->OriginalPrev?dci->OriginalPrev->OriginalInstance:0;
+        ((laListItem*)dci->DBInst->OriginalInstance)->pNext=dci->OriginalNext?dci->OriginalNext->OriginalInstance:0;
+        if(!dci->DBInst->Item.pPrev){ dsp->Instances.pFirst=dci->DBInst; ol->pFirst=dci->DBInst->OriginalInstance; }
+        if(!dci->DBInst->Item.pNext){ dsp->Instances.pLast=dci->DBInst; ol->pLast=dci->DBInst->OriginalInstance; }
+    }
+    for(laDiffCommandInst* dci=dcs->MovedInst.pFirst;dci;dci=dci->Item.pNext){
+        dci->DBInst->Item.pPrev = dci->OriginalPrev; ((laListItem*)dci->DBInst->OriginalInstance)->pPrev=dci->OriginalPrev?dci->OriginalPrev->OriginalInstance:0;
+        dci->DBInst->Item.pNext = dci->OriginalNext; ((laListItem*)dci->DBInst->OriginalInstance)->pNext=dci->OriginalNext?dci->OriginalNext->OriginalInstance:0;
+        if(!dci->DBInst->Item.pPrev){ dsp->Instances.pFirst=dci->DBInst; ol->pFirst=dci->DBInst->OriginalInstance; }
+        if(!dci->DBInst->Item.pNext){ dsp->Instances.pLast=dci->DBInst; ol->pLast=dci->DBInst->OriginalInstance; }
+    }
+}
+
+laDBProp* la_FindDBProp(laDBInst* dbi, laProp* p){
+    for(laDBProp* dbp=dbi->Props.pFirst;dbp;dbp=dbp->Item.pNext){
+        if(dbp->p==p) return dbp;
+    }
+    return 0;
+}
+
+laDiff* laSwapDBState(int Redo){
+    laDiff* diff=MAIN.HeadDifference; if(!diff) return 0;
+    if(Redo){ if(diff==MAIN.Differences.pLast) return 0; }else{ diff=diff->Item.pPrev; if(!diff) return 0; }
+    for(laDiffCommand* dc=diff->Commands.pFirst;dc;dc=dc->Item.pNext){
+        //printf("do %s\n",dc->p->Identifier);
+        laDBProp* dbp=la_FindDBProp(dc->Instance, dc->p);
+        if(!dbp){ printf("Can't find dbp from prop!\n");}
+        switch (dc->p->PropertyType){
+        case LA_PROP_SUB:
+            if(dc->p->UDFIsRefer){
+                LA_SWAP(void*,dc->Data,dbp->Data);
+                laSetActiveInstance(dbp->p, dc->Instance->OriginalInstance, dbp->Data);
+            }else{
+                if(Redo) la_RedoListDifferences(dbp,dc);
+                else     la_UndoListDifferences(dbp,dc);
+            }
+            la_AddUndoPostNode(dc->Instance);
+            break;
+        case LA_PROP_INT: case LA_PROP_ARRAY | LA_PROP_INT:
+            la_RestoreIntDBProp(dbp, dc); la_AddUndoPostNode(dc->Instance); break;
+        case LA_PROP_FLOAT: case LA_PROP_ARRAY | LA_PROP_FLOAT:
+            la_RestoreFloatDBProp(dbp, dc); la_AddUndoPostNode(dc->Instance); break;
+        case LA_PROP_STRING:
+            la_RestoreStringDBProp(dbp, dc); la_AddUndoPostNode(dc->Instance); break;
+        case LA_PROP_ENUM: case LA_PROP_ARRAY | LA_PROP_ENUM:
+            la_RestoreEnumDBProp(dbp, dc); la_AddUndoPostNode(dc->Instance); break;
+        case LA_PROP_RAW:
+            la_RestoreRawDBProp(dbp, dc); la_AddUndoPostNode(dc->Instance); break;
+        default: break;
+        }
+        laPropPack PP={0}; laPropStep PS={0}; PP.LastPs=&PS; PS.p=dbp->p; PS.UseInstance=dc->Instance->OriginalInstance;
+        laNotifyUsersPP(&PP);
+    }
+    if(Redo){ MAIN.HeadDifference=diff->Item.pNext; }
+    else{ MAIN.HeadDifference=diff; }
+    return diff;
+}
+void laUndo(){ laDiff* d; if(d=laSwapDBState(0)){ la_ExecUndoPtrSync(d); } }
+void laRedo(){ laDiff* d; if(d=laSwapDBState(1)){ la_ExecUndoPtrSync(d); } }
+
+void laPrintDBInst(laDBInst* dbi, int Level){
+    if(dbi!=&MAIN.RootDBInst){
+        printf("%*c", Level, ' ');
+        printf("%s  |  %.6x [%.6x] %.6x  |  %.6x [%.6x] %.6x\n",
+            dbi->pc->Identifier, dbi->Item.pPrev, dbi, dbi->Item.pNext,
+            dbi->Item.pPrev?((laDBInst*)dbi->Item.pPrev)->OriginalInstance:0, dbi->OriginalInstance, dbi->Item.pNext?((laDBInst*)dbi->Item.pNext)->OriginalInstance:0);
+    }else{
+        printf("Root:\n");
+    }
+    for(laDBProp* dbp=dbi->Props.pFirst;dbp;dbp=dbp->Item.pNext){
+        if(dbp->p->PropertyType==LA_PROP_SUB && !dbp->p->UDFIsRefer){
+            laDBSubProp* dsp=dbp;
+            for(laDBInst* dbii=dsp->Instances.pFirst;dbii;dbii=dbii->Item.pNext){
+                laPrintDBInst(dbii, Level+4);
+            }
+        }
+    }
+}
+void laPrintDBInstInfo(){
+    laPrintDBInst(&MAIN.RootDBInst, 0);
+}
+
+void laAddRootDBInst(char* path){
+    laPropPack PP={0};
+    if(!la_GetPropFromPath(&PP,0,path,0)) return;
+    if(!MAIN.DBInstLink){ hsh65536Init(&MAIN.DBInstLink); }
+    la_StepPropPack(&PP);
+    laIterateDB(&MAIN.RootDBInst, &PP, 0, 0);
+    la_FreePropStepCache(PP.Go);
+    laDBRecordedProp* rp=lstAppendPointerSized(&MAIN.DBRecordedProps, 0, sizeof(laDBRecordedProp));
+    strSafeSet(&rp->OriginalPath,path);
+}
+
+void laPropPackToLocal(laPropPack* ToPP, laPropPack* pp){
+    if(pp->RawThis) laPropPackToLocal(ToPP, pp->RawThis);
+    for(laPropStep* ps=pp->Go;ps;ps=ps->pNext){
+        la_NewPropStep(ToPP, ps->p, ps->UseInstance, '.');
+    }
+    ToPP->EndInstance = pp->EndInstance;
+}
+laDBProp* laFindDBProp(laDBInst* parent, laProp* p, void* Instance, laDBInst** r_DBInst){
+    laDBProp* rp=0;
+    for(laDBProp* dp=parent->Props.pFirst;dp;dp=dp->Item.pNext){
+        if(dp->p == p) {rp=dp; break;}
+    } if(!rp) return 0;
+    if(rp->p->PropertyType==LA_PROP_SUB && !rp->p->UDFIsRefer && r_DBInst && Instance){
+        laDBSubProp* dsp=rp; for(laDBInst* dbii=dsp->Instances.pFirst;dbii;dbii=dbii->Item.pNext){
+            if(dbii->OriginalInstance == Instance) { *r_DBInst=dbii; break; }
+        }
+    }
+    return rp;
+}
+laDBProp* laFindStartingDBProp(laProp* p, void* Instance, laPropContainer* InstancePC, laDBInst** r_DBInst){
+    if(!Instance||Instance==MAIN.DataRoot.RootInstance){
+        for(laDBProp*dbp=MAIN.RootDBInst.Props.pFirst;dbp;dbp=dbp->Item.pNext){
+            if(dbp->p == p){ *r_DBInst=&MAIN.RootDBInst; return dbp; }
+        }
+    } /* If root not found try to find it in the hash. */
+    if(!MAIN.DBInstLink){ return 0; }
+    laListHandle* l=hsh65536DoHashLongPtr(MAIN.DBInstLink, Instance); if(!l) return 0;
+    for(laListItem* li=l->pFirst;li;li=li->pNext){
+        laDBInst* dbi=(laDBInst*)(((char*)li)-sizeof(laListItem)); if(dbi->OriginalInstance==Instance && dbi->pc==InstancePC){
+            if(p){ for(laDBProp*dbp=dbi->Props.pFirst;dbp;dbp=dbp->Item.pNext){ if(dbp->p == p){ *r_DBInst=dbi; return dbp; } } }
+            else{ *r_DBInst=dbi; return 0; }
+        }
+    }
+    return 0;
+}
+int laRecordDifferences(laPropPack* base, char* path){
+    laPropPack PP={0};
+    la_GetPropFromPath(&PP,base,path,0);
+    la_StepPropPack(&PP);
+    //laPropPackToLocal(&LocalPP, &PP);
+    int success=0;
+
+    laDBInst* FromDBI; //=laSkipDB(&LocalPP, &MAIN.RootDBInst, &dbp);
+    laDBProp* dbp=laFindStartingDBProp(PP.LastPs->p, PP.LastPs->UseInstance, PP.LastPs->p->Container, &FromDBI);
+
+    if(FromDBI && dbp){
+        la_FreeNewerDifferences();
+        laIterateDB(FromDBI, &PP, MAIN.HeadDifference, dbp);
+        if(MAIN.HeadDifference->Commands.pFirst){ success = 1; }
+    }else{
+        success = 0; printf("Prop not recorded as DBInst.\n");
+    }
+
+    la_FreePropStepCache(PP.Go);
+    return success;
+}
+int laRecordInstanceDifferences(void* instance, const char* container){
+    laPropContainer* pc=la_ContainerLookup(container); if(!pc) return 0;
+    laDBInst* FromDBI=0;
+    laFindStartingDBProp(0,instance,pc,&FromDBI); if(!FromDBI) return 0;
+    laPropPack PP={0}; laPropStep PS={0}; PS.UseInstance=instance; PP.LastPs=&PS; 
+    int freed=0, success=0, any=0;
+    for(laProp* p=pc->Props.pFirst;p;p=p->Item.pNext){
+        PS.p = p; laDBProp* dbp=laFindDBProp(FromDBI, p, 0,0);
+        if(FromDBI && dbp){
+            if(!freed){ la_FreeNewerDifferences(); freed=1; }
+            any+=laIterateDB(FromDBI, &PP, MAIN.HeadDifference, dbp);
+            if(MAIN.HeadDifference->Commands.pFirst){ success = 1; }
+        }
+    }
+    if(any){ la_GiveExtraTouched(MAIN.HeadDifference,FromDBI); }
+
+    return success;
+}
+void laRecordAndPush(laPropPack* base, char* path){
+    char buf[256]="Changes in ";;
+    if(laRecordDifferences(base, path)){
+        la_GetPropPackFullPath(base,&buf[strlen(buf)]);if(path){sprintf(&buf[strlen(buf)],".%s",path);}
+        laPushDifferences(buf, 0);
+    }
+}
+void laRecordEverythingAndPush(){
+    for(laDBRecordedProp* rp=MAIN.DBRecordedProps.pFirst;rp;rp=rp->Item.pNext){
+        laRecordAndPush(0, rp->OriginalPath->Ptr);
+    }
+}

+ 896 - 0
source/lagui/la_data.h

@@ -0,0 +1,896 @@
+#pragma once
+
+#include "la_5.h"
+#include "la_tns.h"
+
+/*                                | given to | given to    | array  |      */
+/*                                |  user    | user  calls | setting|      */
+/*                                | callback | and is used | needs  |      */
+/*                                | callback | to recieve  | offset |      */
+/*                                | callback | array config| hint   |      */
+/*                                +----------+-------------+--------+      */
+/*                                |   The    |             |        |      */
+/*                                | DataBlock|    The      |  The   |      */
+/* return value  |    Name        | Instance | Actual Data | Offset |      */
+/*\             /                  \_        \             /      _/       */
+/* \           /                     \_       \           /     _/         */
+/*  \         /                        \_      \         /    _/           */
+/*   \       /                           \_     \       /   _/             */
+/*    \     /                              \     \     /  _/               */
+typedef int (*laArrayGetLenF)(void *);
+typedef int (*laIntGetF)(void *);
+typedef void (*laIntSetF)(void *, int);
+typedef void (*laIntReadF)(void *, int);
+typedef void (*laIntArrayGetAllF)(void *, int *);
+typedef void (*laIntArraySetF)(void *, int, int); //idx,n
+typedef void (*laIntArraySetAllF)(void *, int);
+typedef void (*laIntArraySetAllArrayF)(void *, int *);
+typedef void (*laIntArrayReadAllF)(void *, int *);
+typedef real (*laFloatGetF)(void *);
+typedef void (*laFloatSetF)(void *, real);
+typedef void (*laFloatReadF)(void *, real);
+typedef void (*laFloatArrayGetAllF)(void *, real *);
+typedef void (*laFloatArraySetF)(void *, int, real); //idx,n
+typedef void (*laFloatArraySetAllF)(void *, real);
+typedef void (*laFloatArraySetAllArrayF)(void *, real *);
+typedef void (*laFloatArrayReadAllF)(void *, real *);
+typedef int (*laEnumGetF)(void *);
+typedef int (*laEnumGetLengthF)(void *);
+typedef void (*laEnumSetF)(void *, int);
+typedef void (*laEnumReadF)(void *, int);
+typedef void (*laEnumArraySetF)(void *, int, int); //idx,n
+typedef void (*laEnumArraySetAllF)(void *, int *);
+typedef void (*laEnumArrayReadAllF)(void *, int *);
+typedef void (*laEnumArrayGetAllF)(void *, int *);
+typedef void (*laStringSetF)(void *, char *);
+typedef void (*laStringGetF)(void *, char *copy_result, char** direct_result);
+typedef void (*laStringReadF)(void *, char *);
+typedef int (*laStringGetLenF)(void *);
+
+typedef void (*laSubReadF)(void *, void *);         //from,set
+typedef void *(*laSubGetInstanceF)(void *, void *); //from,iterator
+typedef void (*laSubSetInstanceF)(void *, void *);
+typedef void *(*laSubGetNextF)(void *, void *); //this,iterator
+typedef int (*laSubGetAmountF)(void *);
+typedef int (*laSubGetStateF)(void *);
+typedef int (*laSubSetStateF)(void *, void *, int);
+typedef void *(*laSubTypeDetachedGet)(void *, void *);
+typedef void *(*laSubTypeDetachedGetNext)(void *, void *);
+typedef void *(*laSubGetTypeF)(void *);// inst, returns type ref.
+typedef int (*laSubUIFilterF)(void* parent, void* inst); // 1 show, 0 discard.
+typedef void *(*laSubUIThemeF)(void* parent, void* inst); // return a theme, MAIN.CurrentTheme can always be referenced to produce invert.
+typedef int (*laSubUIGapF)(void* parent, void* inst);
+typedef void* (*laRawGetF)(void *, int* r_size, int* return_is_a_copy);
+typedef int (*laRawGetSizeF)(void *);
+typedef void (*laRawSetF)(void *, void* data, int copy_size);
+
+typedef void (*laContainerPostReadFunc)(void *);
+typedef laPropContainer* (*laGetNodeTypeFunc)(void *);
+typedef void (*laContainerBeforeFreeF)(void *);
+typedef void (*laContainerUndoTouchedF)(void *, u64bit hint);
+typedef void (*laContainerpUDFPropagateF)(void *, void* udf, int Force);
+
+#define LA_PROP_GENERAL_ROOT (1<<7)
+#define LA_PROP_SUB (1<<8)
+#define LA_PROP_INT (1<<9)
+#define LA_PROP_FLOAT (1<<10)
+#define LA_PROP_STRING (1<<11)
+#define LA_PROP_ENUM (1<<12)
+#define LA_PROP_STRING (1<<13)
+#define LA_PROP_ARRAY (1<<14)
+#define LA_PROP_PANEL (1<<15)
+#define LA_PROP_UI (1<<16)
+#define LA_PROP_OPERATOR (1<<17)
+#define LA_PROP_MENU (1<<18)
+#define LA_PROP_SELF_CONDITION (1<<19)
+#define LA_PROP_BIN (1<<20)
+#define LA_PROP_REF_LIST (1<<21)
+#define LA_PROP_GENERIC_BITS (~LA_PROP_ARRAY)
+#define LA_PROP_IS_FOLDER (1<<22)
+#define LA_PROP_IS_FILE   (1<<23)
+#define LA_PROP_RAW       (1<<24)
+
+#define LA_PROP_OTHER_ALLOC (1<<3)
+#define LA_PROP_HYPER_BITS (1|2)
+
+#define LA_RAW_CSTR_MAX_LEN 4096
+
+typedef void (*laUiDefineFunc)(void *uil, void *collection_inst, void *this_inst, void *extra_col, int temlpate_context);
+typedef void (*laPanelDetachedPropFunc)(void *panel);
+
+//typedef void(*laUnlinkFunc)(void*, void*);//this instance,target instance
+
+NEED_STRUCTURE(laCanvasTemplate);
+NEED_STRUCTURE(laKeyMapper);
+
+STRUCTURE(laPropContainer){
+    laListItem Item;
+
+    const char *Identifier;
+    const char *Name;
+    const char *Description;
+
+    uint32_t IconID;
+
+    int NodeSize;
+
+    laContainerBeforeFreeF BeforeFree;
+    laContainerUndoTouchedF UndoTouched;
+    laContainerpUDFPropagateF UDFPropagate;
+    laContainerPostReadFunc PostRead;
+    laContainerPostReadFunc PostReadIm;
+    int Hyper;
+    int OtherAlloc;
+
+    laCanvasTemplate *Template2D;
+
+    laListHandle Props;
+
+    laUiDefineFunc UiDefine;
+
+    laListHandle FailedNodes;
+    laListHandle TrashBin;
+    laListHandle LocalUsers;
+    laListHandle ResourceRegistry;
+
+    int validated;
+};
+
+NEED_STRUCTURE(laUiType);
+NEED_STRUCTURE(laPanel);
+NEED_STRUCTURE(laPropStep);
+
+STRUCTURE(laPropPack){
+    laPropStep *Go;
+    void *EndInstance;
+    laPropStep *LastPs;
+    laPropPack *RawThis;
+    char LastIndex;
+    void *CopyRef;       //Also template creation
+};
+
+STRUCTURE(laProp){
+    laListItem Item;
+    laPropContainer *Container;
+
+    int PropertyType;
+
+    int ReadOnly;
+    //laProp*      Detached;
+    laPropPack DetachedPP;
+
+    int Len;
+
+    char ElementBytes;
+
+    uint32_t IconID;
+
+    const char *Identifier;
+    const char *Name;
+    const char *Description;
+    const char *Prefix;
+    const char *Unit;
+
+    const char *ExtraInstructions;
+
+    laArrayGetLenF GetLen;
+
+    laPropContainer *SubExtra; //?
+    laPropContainer *SubProp;
+
+    laUiDefineFunc UiDefine;
+
+    laUiType *DefaultUiType;
+    int       DefaultFlags;
+
+    int Offset;
+    char OffsetIsPointer;
+    char UDFIsRefer;
+    char UDFNoCreate;
+    char UDFIgnore;
+    char UDFOnly;
+    char UDFIsSingle;
+
+    //int           SignalThrow;
+    //int           SignalCatch;
+
+    u64bit Tag;
+
+    laListHandle UserPanels;
+};
+
+STRUCTURE(laPropUserPanel){
+    laListItem Item;
+    laPanel *Panel;
+    laListHandle UserPacks;
+};
+
+STRUCTURE(laPropUser){
+    laListItem Item;
+    laPropStep *User;
+    unsigned int FrameDistinguish;
+};
+
+STRUCTURE(laPropStep){
+    laPropStep *pNext;
+    laProp *p;
+    char Type;
+    void *UseInstance;
+};
+
+STRUCTURE(laPropLink){
+    laListItem Item;
+    laPropPack Recieve;
+    laSafeString *Identifier;
+    laProp *Prop;
+    laPropStep FakePS;
+    laPropPack PP;
+    void *DataStowage;
+};
+
+STRUCTURE(laIntProp){
+    laProp Base;
+    laIntGetF Get;
+    laIntSetF Set;
+    laIntArraySetF SetArr;
+    laIntArraySetAllF SetAll;
+    laIntArraySetAllArrayF SetAllArr;
+    laIntArrayGetAllF GetAll;
+
+    laIntReadF Read;
+    laIntArrayReadAllF ReadAll;
+
+    int Step;
+    int Min, Max;
+    int DefVal;
+    const int *DefArr;
+
+    int *Detached;
+};
+
+STRUCTURE(laFloatProp){
+    laProp Base;
+    laFloatGetF Get;
+    laFloatSetF Set;
+    laFloatArraySetF SetArr;
+    laFloatArraySetAllF SetAll;
+    laFloatArraySetAllArrayF SetAllArr;
+    laFloatArrayGetAllF GetAll;
+
+    laFloatReadF Read;
+    laFloatArrayReadAllF ReadAll;
+
+    real Step;
+
+    real Min, Max;
+    real DefVal;
+    const real *DefArr;
+
+    real *Detached;
+};
+
+STRUCTURE(laEnumItem){
+    laListItem Item;
+    const char *Identifier;
+    const char *Name;
+    const char *Description;
+    int Index;
+    uint32_t IconID;
+};
+
+STRUCTURE(laEnumProp){
+    laProp Base;
+    laEnumGetF Get;
+    laEnumGetLengthF GetLen;
+    laEnumSetF Set;
+    laEnumArraySetF SetArr;
+    laEnumArraySetAllF SetAll;
+    laEnumArrayGetAllF GetAll;
+
+    laEnumReadF Read;
+    laEnumArrayReadAllF ReadAll;
+
+    laListHandle Items; //id start from 1.
+
+    int DefVal;
+    const int *DefArr;
+
+    int *Detached;
+};
+
+STRUCTURE(laStringProp){
+    laProp Base;
+    laStringGetF Get;
+    laStringSetF Set;
+    laStringGetLenF Getstrlen;
+
+    laStringReadF Read;
+
+    char IsSafeString;
+
+    const char *DefStr;
+
+    char *Detached;
+};
+
+NEED_STRUCTURE(laOperatorType)
+
+STRUCTURE(laOperatorProp){
+    laProp Base;
+    const char *OperatorID;
+    laOperatorType *OperatorType;
+};
+
+STRUCTURE(laRawProp){
+    laProp Base;
+    laRawGetF RawGet;
+    laRawSetF RawSet;
+    laRawGetSizeF RawGetSize;
+};
+
+STRUCTURE(laSubProp){
+    laProp Base;
+    laSubGetInstanceF Get;
+    laSubGetInstanceF GetActive;
+    laSubSetInstanceF Set;
+    laSubGetNextF GetNext;
+    laSubGetStateF GetState;
+    laSubSetStateF SetState;
+    laSubGetAmountF GetAmount;
+    laSubUIFilterF UiFilter;
+    laSubUIThemeF GetTheme;
+    laSubUIGapF GetGap;
+    int ListHandleOffset;
+
+    laSubTypeDetachedGet DetachedGet;
+    laSubTypeDetachedGetNext DetachedGetNext;
+
+    const char *TargetID;
+    laGetNodeTypeFunc GetType;
+
+    void *Detached;
+
+    int IsRefList;
+};
+
+STRUCTURE(laPropIterator){
+    laListItemPointer *Linker;
+    void *Parent;
+    void *Handle;
+};
+
+//STRUCTURE(laPropGroup) {
+//	laListItem Item;
+//	const char * Identifier;
+//	const char * Name;
+//	const char * Description;
+//	//const char * Prefix;
+//	//const char * Unit;
+//
+//	laListHandle Properties;
+//};
+
+STRUCTURE(laResourceFolder){
+    laListItem Item;
+    laSafeString* Path;
+};
+
+STRUCTURE(laRoot){
+    laPropContainer *Root;
+    void *RootInstance;
+};
+STRUCTURE(laUDFPostRead){
+    laListItem Item;
+    void *Instance;
+    laContainerPostReadFunc Func;
+};
+//STRUCTURE(laUDFPointerSync) {
+//	laListItem    Item;
+//	void*        ReadPointer;
+//	void*        ActualPointer;
+//	char *        NUID;
+//};
+//STRUCTURE(laUDFPointerRecord) {
+//	laListItem    Item;
+//	void*        UseInstance;
+//	laSubProp*    SubProp;
+//	void**       PendingReference;
+//	void*        ReadInstance;
+//	char *        NUID;
+//};
+
+
+STRUCTURE(laPtrSync){
+    laListItem Item; //hash
+    void *RefDB;
+    //void*     ReadRef;
+    void *Parent; //key
+    laSubProp *Prop;  //must be sub
+};
+
+STRUCTURE(laPtrSyncCommand){
+    laListItem Item;
+    laPtrSync *Target;
+    void *ReadInstance;
+    laUID ReadNUID;
+};
+
+STRUCTURE(laUDFPropSegment){
+    laListItem Item;
+    laPropPack *PPP;
+    laPropPack PP;
+    laSafeString *Path;
+};
+STRUCTURE(laUDFH2Instance){
+    laListItem Item;
+    laPropContainer* pc;
+    void* Instance;
+};
+STRUCTURE(laUDF){
+    int Opened;
+    FILE *DiskFile;
+    laSafeString *FileName;
+
+    laListHandle     H2Instances;
+    laUDFH2Instance* CurrentH2Instance;
+    
+    laListHandle PropsToOperate;
+    //laListHandle  PointerSync;
+    //laListHandle  PointerRecording;
+    short NumSegmets;
+    short Modified;
+    short HasInstances;
+    short Managed;
+
+    u8bit *FileContent;
+    u64bit Seek;
+
+    long TotalRefs;
+
+    laListHandle HyperRecords; //writing
+
+    //laListHandle  LinkedFiles;    //writing and reading
+    laListHandle OwnHyperItems; //reading
+};
+STRUCTURE(laUDFHyperRecordItem){
+    laListItem Item;
+    void* HyperUserMem;
+    laPropContainer* pc;
+    u64bit Seek;
+};
+STRUCTURE(laUDFRegistry){
+    laListItem Item;
+    laSafeString* Path;
+};
+STRUCTURE(laUDFOwnHyperItem){
+    laListItem Item;
+    laUID NUID;
+    laUDFRegistry* Registry;
+    u64bit Seek;
+};
+STRUCTURE(laTrashRestoreExtra){
+    void *Instance;
+    laListHandle Instances;
+};
+STRUCTURE(laManagedUDF){
+    laListItem Item;
+    laUDF* udf;
+    laSafeString *BaseName; // update together
+    laListHandle PropSegments;
+};
+STRUCTURE(laManagedSaveProp){
+    laListItem Item;
+    laSafeString* Path;
+};
+NEED_STRUCTURE(laUDFContentInstance);
+STRUCTURE(laUDFContentNode){
+    laListItem Item;
+    laListHandle Instances;
+    laSafeString *Identifier;
+    laSafeString *FullPath;
+    unsigned long FileSeek;
+    laPropPack PP;
+    laPropStep FakePS;
+    laUDFContentInstance *Parent;
+};
+STRUCTURE(laUDFContentInstance){
+    laListItem Item;
+    laSafeString *Identifier;
+    u64bit FileSeek;
+    laUDFContentNode *Parent;
+    laListHandle Children;
+};
+
+STRUCTURE(laDiff){
+    laListItem Item;
+    laListHandle Commands;
+    laListHandle ExtraTouched;
+    laSafeString* Description;
+    u64bit Hint;
+};
+STRUCTURE(laDiffExtraTouched){
+    laListItem Item;
+    laDBInst* dbi;//ref, not owner
+};
+STRUCTURE(laDiffCommand){
+    laListItem Item;
+    laDBInst* Instance;
+    laProp* p;
+    void* Data; //for sub, this is dbinst.
+};
+STRUCTURE(laDiffCommandRaw){
+    laListItem Item;
+    laDBInst* Instance;
+    laProp* p;
+    void* Data; int DataSize;
+};
+STRUCTURE(laDiffCommandInst){
+    laListItem Item;
+    laDBInst* OriginalPrev;
+    laDBInst* OriginalNext;
+    laDBInst* BeforePrev;
+    laDBInst* BeforeNext;
+    laDBInst* DBInst;
+};
+STRUCTURE(laDiffCommandSub){
+    laDiffCommand Base;
+    laListHandle AddedInst;
+    laListHandle RemovedInst;
+    laListHandle MovedInst;
+};
+STRUCTURE(laDiffTemp){
+    laListItem Item;
+    void* p;
+    void* tPrev;
+    void* tNext;
+    void* nPrev;
+    void* nNext;
+};
+
+STRUCTURE(laDBRecordedProp){
+    laListItem Item;
+    laSafeString* OriginalPath;
+};
+
+STRUCTURE(laDBInstPendingRelink){
+    laListItem Item;
+    laDBInst* dbi; void* from; void* to;
+};
+STRUCTURE(laDBInst){
+    laListItem Item;
+    laListItem Item2;//DBInstLink
+    void* OriginalInstance;
+    laPropContainer* pc;
+    laListHandle Props;
+    laDiff* CreatedDiff;
+    laDiff* DeletedDiff;
+};
+STRUCTURE(laDBProp){
+    laListItem Item;
+    laProp*    p;
+    void*      Data;
+    //---------------
+};
+;
+STRUCTURE(laDBRawProp){
+    laListItem Item;
+    laProp*    p;
+    void*      Data;
+    //---------------
+    int        DataSize;
+};
+STRUCTURE(laDBSubProp){
+    laListItem Item;
+    laProp*    p;
+    void*      Data;
+    //---------------
+    laListHandle Instances;
+};
+
+STRUCTURE(laDiffPtrSync){
+    laListItem Item;
+    void* instance;
+    laDBProp* dbp;
+    laDiffCommand* dc;
+};
+
+STRUCTURE(laDiffPost){
+    laListItem Item;
+    void* instance;
+    laContainerUndoTouchedF Touched;
+};
+
+
+    //STRUCTURE(laUDFFailNode) {
+    //	laListItemPointer Item;
+    //	laPropContainer*  pc;
+    //};
+
+/* Only little endian are supported right now */
+#define LA_UDF_IDENTIFIER "UDF_LE"
+
+#define LA_UDF_MARK_TIMESTAMP 3
+
+#define LA_UDF_MODE_APPEND 0
+#define LA_UDF_MODE_OVERWRITE 1
+
+#define LA_UDF_SINGLE       (1<<0)
+#define LA_UDF_COLLECTION   (1<<1)
+#define LA_UDF_REFER        (1<<2)
+#define LA_UDF_ITEM         (1<<3) //ItemType
+#define LA_UDF_ACTIVE (1<<4)
+#define LA_UDF_STATE (1<<5)
+#define LA_UDF_REGULAR_MARK_64 (1<<6)
+#define LA_UDF_ARRAY_MARK_64 (1<<7)
+#define LA_UDF_HYPER_ITEM (1<<8)  //ItemType
+#define LA_UDF_SHARE_RESOURCE (1<<9)
+#define LA_UDF_USE_VERSION (1<<10) //Use History
+#define LA_UDF_REGULAR_MARK_32 (1<<10)
+#define LA_UDF_ARRAY_MARK_32 (1<<11)
+#define LA_UDF_STRING_MARK (1<<12)
+#define LA_UDF_HYPER_MARK (1<<13)
+#define LA_UDF_ONLY (1<<14)
+#define LA_UDF_RAW_MARK (1<<14)
+//#define LA_UDF_LINKED_ITEM (1<<15) //ItemType
+#define LA_UDF_IGNORE (1<<16)
+#define LA_DETACHABLE (1<<17)
+#define LA_UDF_VARIABLE_NODE_SIZE (1<<18)
+#define LA_UDF_FIXED_NODE_SIZE (1<<19)
+#define LA_UDF_LOCAL (1<<20)
+#define LA_UDF_IS_RAD (1<<21)
+#define LA_UDF_PRINT_STATICS (1<<22)
+#define LA_UDF_NUID_SEEK (1<<23)
+#define LA_UDF_NUID_LINK_FILES (1<<24)
+#define LA_AS_IDENTIFIER (1<<25)
+#define LA_UDF_USE_LINK_NODE (1<<26)
+#define LA_READ_ONLY (1<<27)
+
+STRUCTURE(laThreadNotifier){
+    laListItem Item;
+    char Path[256];
+};
+
+laPropContainer *laDefineRoot();
+
+NEED_STRUCTURE(laOperatorType)
+NEED_STRUCTURE(laOperator)
+NEED_STRUCTURE(laEvent)
+
+void *laget_ListNext(laListItem *Item, void *UNUSED);
+void *laget_ListPrev(laListItem *Item, void *UNUSED);
+void *laget_List2Next(laListItem2 *Item, void *UNUSED);
+void *laget_List2Prev(laListItem2 *Item, void *UNUSED);
+
+void la_DEBUG_VerifyThisContainer(laPanel *pa, laPropContainer *pc);
+void la_DEBUG_VerifyPanelPropsDestroyed(laPanel *p);
+
+void la_CopyPropPack(laPropPack *From, laPropPack *To);
+void laPropPackToLocal(laPropPack* ToPP, laPropPack* pp);
+
+laPropContainer* la_EnsureSubTarget(laSubProp* sp, void* optional_instance);
+
+laPropContainer *la_ContainerLookup(char *ID);
+laProp *la_PropLookup(laListHandle *lst, char *ID);
+
+void la_UsePropPack(laPropPack *pp, int ForceRecalc);
+void la_StopUsingPropPack(laPropPack *pp);
+void la_SetPropMathcerContext(laPanel *p);
+void laNotifyUsersPP(laPropPack *pp);
+void laNotifyUsersPPPath(laPropPack *pp, char *path);
+void laNotifySubPropUsers(laProp *p, void *Instance);
+void laNotifyUsers(char *Path);
+void laThreadNotifyUsers(char *Path);
+
+int laIsPropertyReadOnly(laPropPack *pp);
+
+int laGetPrefixP(laPropPack *p, char buf[8][64]);
+int laGetPrefix(laProp *p, char buf[8][64]);
+
+laPropContainer* laGetInstanceType(laPropPack* pp, void* instance);
+laUiDefineFunc* laGetPropertyUiDefine(laPropPack* pp, void* instance);
+
+int laSetInt(laPropPack *pp, int n);
+int laGetInt(laPropPack *pp);
+int laSetFloat(laPropPack *pp, real n);
+real laGetFloat(laPropPack *pp);
+int laGetArrayLength(laPropPack *pp);
+int laSetIntArraySingle(laPropPack *pp, int index, int n);
+int laSetIntArrayAll(laPropPack *pp, int n);
+int laSetIntArrayAllArray(laPropPack *pp, int *arr);
+int laGetIntArray(laPropPack *pp, int *result);
+int laSetFloatArraySingle(laPropPack *pp, int index, real n);
+int laSetFloatArrayAll(laPropPack *pp, real n);
+int laSetFloatArrayAllArray(laPropPack *pp, real *arr);
+int laGetFloatArray(laPropPack *pp, real *result);
+laEnumItem *laGetEnum(laPropPack *pp);
+laEnumItem *laGetEnumEntryLen(laPropPack *pp);
+laEnumItem *laGetEnumArrayIndexed(laPropPack *pp, int index);
+int laGetEnumArray(laPropPack *pp, laEnumItem **result);
+laEnumItem *laGetEnumFromIdentifier(laEnumProp *p, char *Identifier);
+int laEnumHasIcon(laPropPack *pp);
+int laSetEnumExternal(laPropPack *pp, int n);
+int laSetEnum(laPropPack *pp, int n);
+int laSetEnumArrayIndexedExternal(laPropPack *pp, int index, int n);
+int laSetEnumArrayIndexed(laPropPack *pp, int index, int n);
+int laSetEnumArrayAllArray(laPropPack* pp, laEnumItem** ei);
+int laSetEnumArrayAll(laPropPack* pp, int EnumN);
+int laSetString(laPropPack *pp, char *str);
+int laGetString(laPropPack *pp, char *result, char** direct_result);
+int laActuateProp(laPropPack *This, laPropPack *RunPP, laOperator *OptionalFrom, laEvent *e);
+int laGetIntRange(laPropPack *pp, int *min, int *max);
+int laGetFloatRange(laPropPack *pp, real *min, real *max);
+void* laGetRaw(laPropPack *pp, int* r_size, int* return_is_a_copy);
+int laSetRaw(laPropPack *pp, void* data, int _size);
+
+void laMarkPropChanged(laPropPack* pp);
+
+void *la_FindMatchingInstance(void *From, laProp *Sub, laProp *p, laPropStep *Value);
+
+void la_FreePropStepCache(laPropStep *GoTarget);
+void la_StepPropPack(laPropPack *pp);
+
+void la_GetPropPackFullPath(laPropPack *pp, char *result);
+void la_GetPropPackPath(laPropPack *pp, char *result);
+
+laItemUserLinker *laUseDataBlock(void* HyperUserMem, laProp *Which, unsigned int FrameDistinguish, void *User, laUserRemoveFunc Remover, int ForceRecalc);
+void laStopUsingDataBlock(void* HyperUserMem, laProp *prop, laPanel *p);
+void laDataBlockNoLongerExists(void *HyperUserMem, laListHandle* UserList);
+
+void laThrowToTrashBin(void* Data, char *ContainerString);
+
+
+void la_FreeProperty(laProp* p);
+void la_FreePropertyContainer(laPropContainer* pc);
+
+laPropContainer *laAddPropertyContainer(const char *Identifier, const char *Name, const char *Description, uint32_t IconID, laUiDefineFunc DefaultUiDefine,
+                                        int NodeSize, laContainerPostReadFunc PostRead, laContainerPostReadFunc PostReadIm, int IsHyper);
+void laPropContainerExtraFunctions(laPropContainer* pc, laContainerBeforeFreeF BeforeFree, laContainerUndoTouchedF UndoTouched, laContainerpUDFPropagateF UDFPropagate);
+const char *la_GetPropertyTypeString(int Type);
+
+NEED_STRUCTURE(laWidget);
+
+laProp *la_CreateProperty(laPropContainer *Container, int Type, const char *Identifier, const char *Name, const char *Description,
+                          const char *Prefix, const char *Unit, laWidget* DefaultWidget, u64bit Tag);
+laProp *la_MakeDetachedProp(laPanel* p, const char *From, const char *Rename);
+laProp *laAddIntProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                         const char *Prefix, const char *Unit, int Max, int Min, int Step, int DefVal, const int *DefArr,
+                         int OffsetSize, laIntGetF Get, laIntSetF Set, int ArrayLength, laArrayGetLenF GetLen,
+                         laIntArraySetF SetArr, laIntArrayGetAllF GetAll, laIntArraySetAllF SetAll, laIntArraySetAllArrayF SetAllArr,
+                         laIntReadF Read, laIntArrayReadAllF ReadAll,
+                         u64bit Tag);
+
+laProp *laAddFloatProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                           const char *Prefix, const char *Unit, real Max, real Min, real Step, real DefVal, const real *DefArr,
+                           int OffsetSize, laFloatGetF Get, laFloatSetF Set, int ArrayLength, laArrayGetLenF GetLen,
+                           laFloatArraySetF SetArr, laFloatArrayGetAllF GetAll, laFloatArraySetAllF SetAll, laFloatArraySetAllArrayF SetAllArr,
+                           laFloatReadF Read, laFloatArrayReadAllF ReadAll,
+                           u64bit Tag);
+
+laProp *laAddEnumProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                          const char *Prefix, const char *Unit, int DefVal, const int *DefArr,
+                          int OffsetSize, laEnumGetF Get, laEnumSetF Set, int ArrayLength, laArrayGetLenF GetLen,
+                          laEnumArraySetF SetArr, laEnumArrayGetAllF GetAll, laEnumArraySetAllF SetAll,
+                          laEnumReadF Read, laEnumArrayReadAllF ReadAll,
+                          u64bit Tag);
+
+int laAddEnumItem(laProp *p, const char *Identifier, const char *Name, const char *Description, uint32_t IconID);
+int laAddEnumItemAs(laProp *p, const char *Identifier, const char *Name, const char *Description, int Index, uint32_t IconID);
+
+laProp *laAddStringProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, laWidget* DefaultWidget,
+                            const char *Prefix, const char *Unit, const char *DefStr,
+                            int IsSafeString, int OffsetSize, laStringGetLenF GetLen, laStringGetF Get, laStringSetF Set,
+                            laStringReadF Read,
+                            u64bit Tag);
+
+laProp *laAddSubGroup(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description,
+                      const char *TargetId, laGetNodeTypeFunc GetType, laWidget* DefaultWidget, laUiDefineFunc DefaultUiDef,
+                      int OffsetSize, laSubGetInstanceF Get, laSubGetInstanceF GetActive, laSubGetNextF GetNext, laSubSetInstanceF Set,
+                      laSubGetStateF GetState, laSubSetStateF SetState, int ListHandleOffset, u64bit Tag);
+void laSubGroupExtraFunctions(laProp* p, laSubUIFilterF* UiFilter, laSubUIThemeF* GetTheme, laSubUIGapF GetGap);
+void laSubGroupDetachable(laProp *SubProp, laSubTypeDetachedGet DetachedGet, laSubTypeDetachedGetNext DetachedGetNext);
+
+laProp *laAddOperatorProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description,
+                              const char *OperatorID, uint32_t IconID, laWidget* DefaultWidget);
+
+laProp *laAddRawProperty(laPropContainer *Container, const char *Identifier, const char *Name, const char *Description, int OffsetSize, laRawGetSizeF GetSize, laRawGetF RawGet, laRawSetF RawSet, u64bit Tag);
+
+//void laPropertySignal(laProp* p, int Throw, int Catch);
+
+NEED_STRUCTURE(laBoxedTheme);
+
+void *laGetInstance(laProp *sub, void *ThisInstance, laPropIterator *pi);
+void *laGetNextInstance(laProp *sub, void *FromInstance, laPropIterator *pi);
+void *laGetActiveInstanceStrict(laProp *sub, void *FromInstance);
+void *laGetActiveInstance(laProp *sub, void *FromInstance, laPropIterator *pi);
+void laSetActiveInstance(laProp *sub, void *FromInstance, void *Instance);
+void laAppendInstance(laSubProp *sub, void *FromInstance, void *Instance);
+int laGetUiState(laProp *sub, void *Instance);
+laBoxedTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance);
+int laGetUiGap(laProp *sub, void* parent, void *Instance);
+int laCanGetState(laProp *sub);
+int laCanGetTheme(laProp *sub);
+int laCanGetGap(laProp *sub);
+int laSetState(laProp *sub, void *FromInstance, void *Instance, int State);
+
+laPropContainer *la_SetGeneralRoot(laPropContainer **GeneralRoot, const char *Identifier, const char *Name, const char *Description);
+
+int la_GetPropFromPath(laPropPack *Self, laPropPack *Base, const char *Path, void **SpecifiedInstance);
+laProp *la_GetGeneralPropFromPath(laProp *General, const char *Path);
+
+int laValidateProperties();
+
+void laSetRootInstance(void *root);
+
+void la_RegisterMainUiTypes();
+void la_RegisterMainThemes();
+void la_RegisterInternalTemplates();
+void la_RegisterInternalProps();
+
+void la_PrintPropStructure();
+
+laProp *la_GetGeneralProp(laProp *p);
+
+void* laget_InstanceActiveUDF(void* instance);
+void laset_InstanceUDF(void* instance, void* set);
+
+void la_UDFAppendSharedTypePointer(char *ID, void *Pointer);
+
+void la_AppendLinkedFile(laUDF *File);
+
+void la_GetWorkingDirectoryInternal();
+int laGetRelativeDirectory(char *FullFrom, char *FullTo, char *Result);
+void laGetUDFRelativeDirectory(laUDF *From, laUDF *To, char *Result);
+void laGetFullPath(char *FullFrom, char *Relative, char *Result);
+
+laUDF *laPrepareUDF(char *FileName);
+int laWriteProp(laUDF *udf, char *Path);
+int laWritePropP(laUDF *udf, laPropPack *pp);
+int laPackUDF(laUDF *udf, int UseInstanceList);
+
+void laSaveProp(char* path);
+void laClearSaveProp();
+
+int laRegisterModifications(int ReturnIfAnyMod, int ReturnIfAnyEmpty, int* rempty, int RegisterToUDF);
+
+laUDF *laOpenUDF(char *FileName, int ReadToMemory, laUDFRegistry* ReadRegistryRef, laManagedUDF** UseManaged);
+void laCloseUDF(laUDF *udf);
+int laExtractUDF(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *Parent);
+int laExtractUDFContent(laUDF *udf, laManagedUDF* mUDF, int Mode, laListHandle *ContentNodes);
+
+laUDFOwnHyperItem* laFindHyperItem(laPropContainer* pc, char* uid);
+laUDFRegistry* laFindUDFRegistry(char* Path);
+laUDFRegistry* laCreateUDFRegistry(char* Path);
+void laClearUDFRegistries();
+void laRefreshUDFRegistries();
+
+laManagedUDF* la_FindManagedUDF(char* FileName);
+laManagedUDF* la_EnsureManagedUDF(char* FileName, int PutAtTop);
+void la_MakeDummyManagedUDF();
+void laStopManageUDF(laManagedUDF* m);
+void laClearManagedUDF();
+
+void laSaveManagedUDF();
+
+void laPropagateUDF(laPropContainer* pc, void* inst, int force);
+
+//================== manifest
+
+void laAddResourceFolder(char* Path);
+void laRemoveResourceFolder(laResourceFolder* rf);
+void la_ClearUDFRegistryAndFolders();
+
+//================== undo
+
+
+void laPrintDBInstInfo();
+void la_NoLongerRecordUndo();
+
+void laAddRootDBInst(char* path);
+void laPushDifferences(char* Description, u64bit hint);
+int laRecordDifferences(laPropPack* base, char* path);
+int laRecordInstanceDifferences(void* instance, const char* container);
+void laRecordAndPush(laPropPack* base, char* path);
+void laRecordEverythingAndPush();
+
+void laUndo();
+void laRedo();

+ 245 - 0
source/lagui/la_icon.h

@@ -0,0 +1,245 @@
+#pragma once
+
+// arrows
+#ifndef _LA_ICO_ARROWS
+#define _LA_ICO_ARROWS\
+"←↑→↓↔↕↖↗↘↙↩↪↯⇦⇧⇨⇩⇪⇫⇬⇭⇮⇯⇰⇳⤡⤢⤴⤵🠀🠁🠂🠃🠄🠅🠆🠇🠈🠉🠊"\
+"🠋🠐🠑🠒🠓🠔🠕🠖🠗🠘🠙🠚🠛🠜🠝🠞🠟🠠🠡🠢🠣🠤🠥🠦🠧🠨🠩🠪🠫🠬🠭🠮🠯🠰🠱🠲🠳🠴🠵🠶"\
+"🠷🠸🠹🠺🠻🠼🠽🠾🠿🡀🡁🡂🡃🡄🡅🡆🡇🡐🡑🡒🡓🡔🡕🡖🡗🡘🡙🡠🡡🡢🡣🡤🡥🡦🡧🡨🡩🡪🡫🡬"\
+"🡭🡮🡯🡰🡱🡲🡳🡴🡵🡶🡷🡸🡹🡺🡻🡼🡽🡾🡿🢀🢁🢂🢃🢄🢅🢆🢇🢐🢑🢒🢓🢔🢕🢖🢗🢘🢙🢚🢛🢜"\
+"🢝🢞🢟🢠🢡🢢🢣🢤🢥🢦🢧🢨🢩🢪🢫🢬🢭🢰🢱"
+;
+#endif
+
+// dingbats
+#ifndef _LA_ICO_DINGBATS
+#define _LA_ICO_DINGBATS\
+"∘∙⊙⋄⋅⋆✀✁✂✃✄✅✆✇✈✉✊✋✌✍✎✏✐✑✒✓✔✕✖✗✘✙✚✛✜✝✞✟✠✡"\
+"✢✣✤✥✦✧✨✩✪✫✬✭✮✯✰✱✲✳✴✵✶✷✸✹✺✻✼✽✾✿❀❁❂❃❄❅❆❇❈❉"\
+"❊❋❌❍❎❏❐❑❒❓❔❕❖❗❘❙❚❛❜❝❞❟❠❡❢❣❤❥❦❧❨❩❪❫❬❭❮❯❰❱"\
+"❲❳❴❵❶❷❸❹❺❻❼❽❾❿➀➁➂➃➄➅➆➇➈➉➊➋➌➍➎➏➐➑➒➓➔➕➖➗➘➙"\
+"➚➛➜➝➞➟➠➡➢➣➤➥➦➧➨➩➪➫➬➭➮➯➰➱➲➳➴➵➶➷➸➹➺➻➼➽➾➿🙐🙑"\
+"🙒🙓🙔🙕🙖🙗🙘🙙🙚🙛🙜🙝🙞🙟🙠🙡🙢🙣🙤🙥🙦🙧🙨🙩🙪🙫🙬🙭🙮🙯🙰🙱🙲🙳🙴🙵🙶🙷🙸🙹"\
+"🙺🙻🙼🙽🙾🙿"
+;
+#endif
+
+// tech
+#ifndef _LA_ICO_TECH
+#define _LA_ICO_TECH\
+"⌀⌁⌂⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌⌍⌎⌏⌑⌒⌓⌔⌕⌖⌗⌘⌚⌛⌜⌝⌞⌟⌢⌣⌤⌥⌦⌧⌨〈〉⌫"\
+"⌬⌭⌮⌯⌰⌱⌲⌳⌴⌵⍻⍼⍽⍾⍿⎀⎁⎂⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌⎍⎎⎏⎐⎑⎒⎓⎔⎖⎗⎘⎙"\
+"⎚⎯⎾⎿⏀⏁⏂⏃⏄⏅⏆⏇⏈⏉⏊⏋⏌⏍⏎⏏⏐⏑⏒⏓⏔⏕⏖⏗⏘⏙⏚⏛⏢⏣⏤⏥⏦⏧⏨⏩"\
+"⏪⏫⏬⏭⏮⏯⏰⏱⏲⏳⏴⏵⏶⏷⏸⏹⏺⏻⏼⏽⏾⏿"
+;
+#endif
+
+// geom
+#ifndef _LA_ICO_GEOM
+#define _LA_ICO_GEOM\
+"■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀◁◂◃◄◅◆◇"\
+"◈◉◊○◌◍◎●◐◑◒◓◔◕◖◗◘◙◚◛◜◝◞◟◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯"\
+"◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿🞀🞁🞂🞃🞄🞅🞆🞇🞈🞉🞊🞋🞌🞍🞎🞏🞐🞑🞒🞓🞔🞕🞖🞗"\
+"🞘🞙🞚🞛🞜🞝🞞🞟🞠🞡🞢🞣🞤🞥🞦🞧🞨🞩🞪🞫🞬🞭🞮🞯🞰🞱🞲🞳🞴🞵🞶🞷🞸🞹🞺🞻🞼🞽🞾🞿"\
+"🟀🟁🟂🟃🟄🟅🟆🟇🟈🟉🟊🟋🟌🟍🟎🟏🟐🟑🟒🟓🟔🟕🟖🟗🟘🟠🟡🟢🟣🟤🟥🟦🟧🟨🟩🟪🟫🟰"
+;
+#endif
+
+// misc
+#ifndef _LA_ICO_MISC
+#define _LA_ICO_MISC\
+"☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧"\
+"☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏"\
+"♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷"\
+"♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟"\
+"⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇"\
+"⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯"\
+"⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿⬀⬁⬂⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌⬍⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛"\
+"⬜⬝⬞⬟⬠⬡⬢⬣⬤⬥⬦⬧⬨⬩⬪⬫⬬⬭⬮⬯⭍⭎⭏⭐⭑⭒⭓⭔⭕⭖⭗⭘⭙⭚⭛⭜⭝⭞⭟⭠"\
+"⭡⭢⭣⭤⭥⭦⭧⭨⭩⭪⭫⭬⭭⭮⭯⭰⭱⭲⭳⭶⭷⭸⭹⭺⭻⭼⭽⭾⭿⮀⮁⮂⮃⮄⮅⮆⮇⮈⮉⮊"\
+"⮋⮌⮍⮎⮏⮐⮑⮒⮓⮔⮕⮗⮘⮙⮚⮛⮜⮝⮞⮟⮠⮡⮢⮣⮤⮥⮦⮧⮨⮩⮪⮫⮬⮭⮮⮯⮰⮱⮲⮳"\
+"⮴⮵⮶⮷⮸⮹⮺⮻⮼⮽⮾⮿⯀⯁⯂⯃⯄⯅⯆⯇⯈⯉⯊⯋⯌⯍⯎⯏⯐⯑⯒⯓⯔⯕⯖⯗⯘⯙⯚⯛"\
+"⯜⯝⯞⯟⯠⯡⯢⯣⯤⯥⯦⯧⯨⯩⯪⯫⯬⯭⯮⯯⯰⯱⯲⯳⯴⯵⯶⯷⯸⯹⯺⯻⯼⯽⯿🌀🌁🌂🌃🌄"\
+"🌅🌆🌇🌈🌉🌊🌋🌌🌍🌎🌏🌐🌑🌒🌓🌔🌕🌖🌗🌘🌙🌚🌛🌜🌝🌞🌟🌠🌡🌢🌣🌤🌥🌦🌧🌨🌩🌪🌫🌬"\
+"🌭🌮🌯🌰🌱🌲🌳🌴🌵🌶🌷🌸🌹🌺🌻🌼🌽🌾🌿🍀🍁🍂🍃🍄🍅🍆🍇🍈🍉🍊🍋🍌🍍🍎🍏🍐🍑🍒🍓🍔"\
+"🍕🍖🍗🍘🍙🍚🍛🍜🍝🍞🍟🍠🍡🍢🍣🍤🍥🍦🍧🍨🍩🍪🍫🍬🍭🍮🍯🍰🍱🍲🍳🍴🍵🍶🍷🍸🍹🍺🍻🍼"\
+"🍽🍾🍿🎀🎁🎂🎃🎄🎅🎆🎇🎈🎉🎊🎋🎌🎍🎎🎏🎐🎑🎒🎓🎔🎕🎖🎗🎘🎙🎚🎛🎜🎝🎞🎟🎠🎡🎢🎣🎤"\
+"🎥🎦🎧🎨🎩🎪🎫🎬🎭🎮🎯🎰🎱🎲🎳🎴🎵🎶🎷🎸🎹🎺🎻🎼🎽🎾🎿🏀🏁🏂🏃🏄🏅🏆🏇🏈🏉🏊🏋🏌"\
+"🏍🏎🏏🏐🏑🏒🏓🏔🏕🏖🏗🏘🏙🏚🏛🏜🏝🏞🏟🏠🏡🏢🏣🏤🏥🏦🏧🏨🏩🏪🏫🏬🏭🏮🏯🏰🏱🏲🏳🏴"\
+"🏵🏶🏷🏸🏹🏺🏻🏼🏽🏾🏿🐀🐁🐂🐃🐄🐅🐆🐇🐈🐉🐊🐋🐌🐍🐎🐏🐐🐑🐒🐓🐔🐕🐖🐗🐘🐙🐚🐛🐜"\
+"🐝🐞🐟🐠🐡🐢🐣🐤🐥🐦🐧🐨🐩🐪🐫🐬🐭🐮🐯🐰🐱🐲🐳🐴🐵🐶🐷🐸🐹🐺🐻🐼🐽🐾🐿👀👁👂👃👄"\
+"👅👆👇👈👉👊👋👌👍👎👏👐👑👒👓👔👕👖👗👘👙👚👛👜👝👞👟👠👡👢👣👤👥👦👧👨👩👪👫👬"\
+"👭👮👯👰👱👲👳👴👵👶👷👸👹👺👻👼👽👾👿💀💁💂💃💄💅💆💇💈💉💊💋💌💍💎💏💐💑💒💓💔"\
+"💕💖💗💘💙💚💛💜💝💞💟💠💡💢💣💤💥💦💧💨💩💪💫💬💭💮💯💰💱💲💳💴💵💶💷💸💹💺💻💼"\
+"💽💾💿📀📁📂📃📄📅📆📇📈📉📊📋📌📍📎📏📐📑📒📓📔📕📖📗📘📙📚📛📜📝📞📟📠📡📢📣📤"\
+"📥📦📧📨📩📪📫📬📭📮📯📰📱📲📳📴📵📶📷📸📹📺📻📼📽📾📿🔀🔁🔂🔃🔄🔅🔆🔇🔈🔉🔊🔋🔌"\
+"🔍🔎🔏🔐🔑🔒🔓🔔🔕🔖🔗🔘🔙🔚🔛🔜🔝🔞🔟🔠🔡🔢🔣🔤🔥🔦🔧🔨🔩🔪🔫🔬🔭🔮🔯🔰🔱🔲🔳🔴"\
+"🔵🔶🔷🔸🔹🔺🔻🔼🔽🔾🔿🕀🕁🕂🕃🕄🕅🕆🕇🕈🕉🕊🕋🕌🕍🕎🕏🕐🕑🕒🕓🕔🕕🕖🕗🕘🕙🕚🕛🕜"\
+"🕝🕞🕟🕠🕡🕢🕣🕤🕥🕦🕧🕨🕩🕪🕫🕬🕭🕮🕯🕰🕱🕲🕳🕴🕵🕶🕷🕸🕹🕺🕻🕼🕽🕾🕿🖀🖁🖂🖃🖄"\
+"🖅🖆🖇🖈🖉🖊🖋🖌🖍🖎🖏🖐🖑🖒🖓🖔🖕🖖🖗🖘🖙🖚🖛🖜🖝🖞🖟🖠🖡🖢🖣🖤🖥🖦🖧🖨🖩🖪🖫🖬"\
+"🖭🖮🖯🖰🖱🖲🖳🖴🖵🖶🖷🖸🖹🖺🖻🖼🖽🖾🖿🗀🗁🗂🗃🗄🗅🗆🗇🗈🗉🗊🗋🗌🗍🗎🗏🗐🗑🗒🗓🗔"\
+"🗕🗖🗗🗘🗙🗚🗛🗜🗝🗞🗟🗠🗡🗢🗣🗤🗥🗦🗧🗨🗩🗪🗫🗬🗭🗮🗯🗰🗱🗲🗳🗴🗵🗶🗷🗸🗹🗺🗻🗼"\
+"🗽🗾🗿"
+;
+#endif
+
+// math
+#ifndef _LA_ICO_MATH
+#define _LA_ICO_MATH\
+"⦁⦿⧫"
+;
+#endif
+
+// braille
+#ifndef _LA_ICO_BRAILLE
+#define _LA_ICO_BRAILLE\
+"⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧"\
+"⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿⡀⡁⡂⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌⡍⡎⡏"\
+"⡐⡑⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜⡝⡞⡟⡠⡡⡢⡣⡤⡥⡦⡧⡨⡩⡪⡫⡬⡭⡮⡯⡰⡱⡲⡳⡴⡵⡶⡷"\
+"⡸⡹⡺⡻⡼⡽⡾⡿⢀⢁⢂⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌⢍⢎⢏⢐⢑⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜⢝⢞⢟"\
+"⢠⢡⢢⢣⢤⢥⢦⢧⢨⢩⢪⢫⢬⢭⢮⢯⢰⢱⢲⢳⢴⢵⢶⢷⢸⢹⢺⢻⢼⢽⢾⢿⣀⣁⣂⣃⣄⣅⣆⣇"\
+"⣈⣉⣊⣋⣌⣍⣎⣏⣐⣑⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜⣝⣞⣟⣠⣡⣢⣣⣤⣥⣦⣧⣨⣩⣪⣫⣬⣭⣮⣯"\
+"⣰⣱⣲⣳⣴⣵⣶⣷⣸⣹⣺⣻⣼⣽⣾⣿"
+;
+#endif
+
+// egyptian
+#ifndef _LA_ICO_EGYPTIAN
+#define _LA_ICO_EGYPTIAN\
+"𓀀𓀁𓀂𓀃𓀄𓀅𓀆𓀇𓀈𓀉𓀊𓀋𓀌𓀍𓀎𓀏𓀐𓀑𓀒𓀓𓀔𓀕𓀖𓀗𓀘𓀙𓀚𓀛𓀜𓀝𓀞𓀟𓀠𓀡𓀢𓀣𓀤𓀥𓀦𓀧"\
+"𓀨𓀩𓀪𓀫𓀬𓀭𓀮𓀯𓀰𓀱𓀲𓀳𓀴𓀵𓀶𓀷𓀸𓀹𓀺𓀻𓀼𓀽𓀾𓀿𓁀𓁁𓁂𓁃𓁄𓁅𓁆𓁇𓁈𓁉𓁊𓁋𓁌𓁍𓁎𓁏"\
+"𓁐𓁑𓁒𓁓𓁔𓁕𓁖𓁗𓁘𓁙𓁚𓁛𓁜𓁝𓁞𓁟𓁠𓁡𓁢𓁣𓁤𓁥𓁦𓁧𓁨𓁩𓁪𓁫𓁬𓁭𓁮𓁯𓁰𓁱𓁲𓁳𓁴𓁵𓁶𓁷"\
+"𓁸𓁹𓁺𓁻𓁼𓁽𓁾𓁿𓂀𓂁𓂂𓂃𓂄𓂅𓂆𓂇𓂈𓂉𓂊𓂋𓂌𓂍𓂎𓂏𓂐𓂑𓂒𓂓𓂔𓂕𓂖𓂗𓂘𓂙𓂚𓂛𓂜𓂝𓂞𓂟"\
+"𓂠𓂡𓂢𓂣𓂤𓂥𓂦𓂧𓂨𓂩𓂪𓂫𓂬𓂭𓂮𓂯𓂰𓂱𓂲𓂳𓂴𓂵𓂶𓂷𓂸𓂹𓂺𓂻𓂼𓂽𓂾𓂿𓃀𓃁𓃂𓃃𓃄𓃅𓃆𓃇"\
+"𓃈𓃉𓃊𓃋𓃌𓃍𓃎𓃏𓃐𓃑𓃒𓃓𓃔𓃕𓃖𓃗𓃘𓃙𓃚𓃛𓃜𓃝𓃞𓃟𓃠𓃡𓃢𓃣𓃤𓃥𓃦𓃧𓃨𓃩𓃪𓃫𓃬𓃭𓃮𓃯"\
+"𓃰𓃱𓃲𓃳𓃴𓃵𓃶𓃷𓃸𓃹𓃺𓃻𓃼𓃽𓃾𓃿𓄀𓄁𓄂𓄃𓄄𓄅𓄆𓄇𓄈𓄉𓄊𓄋𓄌𓄍𓄎𓄏𓄐𓄑𓄒𓄓𓄔𓄕𓄖𓄗"\
+"𓄘𓄙𓄚𓄛𓄜𓄝𓄞𓄟𓄠𓄡𓄢𓄣𓄤𓄥𓄦𓄧𓄨𓄩𓄪𓄫𓄬𓄭𓄮𓄯𓄰𓄱𓄲𓄳𓄴𓄵𓄶𓄷𓄸𓄹𓄺𓄻𓄼𓄽𓄾𓄿"\
+"𓅀𓅁𓅂𓅃𓅄𓅅𓅆𓅇𓅈𓅉𓅊𓅋𓅌𓅍𓅎𓅏𓅐𓅑𓅒𓅓𓅔𓅕𓅖𓅗𓅘𓅙𓅚𓅛𓅜𓅝𓅞𓅟𓅠𓅡𓅢𓅣𓅤𓅥𓅦𓅧"\
+"𓅨𓅩𓅪𓅫𓅬𓅭𓅮𓅯𓅰𓅱𓅲𓅳𓅴𓅵𓅶𓅷𓅸𓅹𓅺𓅻𓅼𓅽𓅾𓅿𓆀𓆁𓆂𓆃𓆄𓆅𓆆𓆇𓆈𓆉𓆊𓆋𓆌𓆍𓆎𓆏"\
+"𓆐𓆑𓆒𓆓𓆔𓆕𓆖𓆗𓆘𓆙𓆚𓆛𓆜𓆝𓆞𓆟𓆠𓆡𓆢𓆣𓆤𓆥𓆦𓆧𓆨𓆩𓆪𓆫𓆬𓆭𓆮𓆯𓆰𓆱𓆲𓆳𓆴𓆵𓆶𓆷"\
+"𓆸𓆹𓆺𓆻𓆼𓆽𓆾𓆿𓇀𓇁𓇂𓇃𓇄𓇅𓇆𓇇𓇈𓇉𓇊𓇋𓇌𓇍𓇎𓇏𓇐𓇑𓇒𓇓𓇔𓇕𓇖𓇗𓇘𓇙𓇚𓇛𓇜𓇝𓇞𓇟"\
+"𓇠𓇡𓇢𓇣𓇤𓇥𓇦𓇧𓇨𓇩𓇪𓇫𓇬𓇭𓇮𓇯𓇰𓇱𓇲𓇳𓇴𓇵𓇶𓇷𓇸𓇹𓇺𓇻𓇼𓇽𓇾𓇿𓈀𓈁𓈂𓈃𓈄𓈅𓈆𓈇"\
+"𓈈𓈉𓈊𓈋𓈌𓈍𓈎𓈏𓈐𓈑𓈒𓈓𓈔𓈕𓈖𓈗𓈘𓈙𓈚𓈛𓈜𓈝𓈞𓈟𓈠𓈡𓈢𓈣𓈤𓈥𓈦𓈧𓈨𓈩𓈪𓈫𓈬𓈭𓈮𓈯"\
+"𓈰𓈱𓈲𓈳𓈴𓈵𓈶𓈷𓈸𓈹𓈺𓈻𓈼𓈽𓈾𓈿𓉀𓉁𓉂𓉃𓉄𓉅𓉆𓉇𓉈𓉉𓉊𓉋𓉌𓉍𓉎𓉏𓉐𓉑𓉒𓉓𓉔𓉕𓉖𓉗"\
+"𓉘𓉙𓉚𓉛𓉜𓉝𓉞𓉟𓉠𓉡𓉢𓉣𓉤𓉥𓉦𓉧𓉨𓉩𓉪𓉫𓉬𓉭𓉮𓉯𓉰𓉱𓉲𓉳𓉴𓉵𓉶𓉷𓉸𓉹𓉺𓉻𓉼𓉽𓉾𓉿"\
+"𓊀𓊁𓊂𓊃𓊄𓊅𓊆𓊇𓊈𓊉𓊊𓊋𓊌𓊍𓊎𓊏𓊐𓊑𓊒𓊓𓊔𓊕𓊖𓊗𓊘𓊙𓊚𓊛𓊜𓊝𓊞𓊟𓊠𓊡𓊢𓊣𓊤𓊥𓊦𓊧"\
+"𓊨𓊩𓊪𓊫𓊬𓊭𓊮𓊯𓊰𓊱𓊲𓊳𓊴𓊵𓊶𓊷𓊸𓊹𓊺𓊻𓊼𓊽𓊾𓊿𓋀𓋁𓋂𓋃𓋄𓋅𓋆𓋇𓋈𓋉𓋊𓋋𓋌𓋍𓋎𓋏"\
+"𓋐𓋑𓋒𓋓𓋔𓋕𓋖𓋗𓋘𓋙𓋚𓋛𓋜𓋝𓋞𓋟𓋠𓋡𓋢𓋣𓋤𓋥𓋦𓋧𓋨𓋩𓋪𓋫𓋬𓋭𓋮𓋯𓋰𓋱𓋲𓋳𓋴𓋵𓋶𓋷"\
+"𓋸𓋹𓋺𓋻𓋼𓋽𓋾𓋿𓌀𓌁𓌂𓌃𓌄𓌅𓌆𓌇𓌈𓌉𓌊𓌋𓌌𓌍𓌎𓌏𓌐𓌑𓌒𓌓𓌔𓌕𓌖𓌗𓌘𓌙𓌚𓌛𓌜𓌝𓌞𓌟"\
+"𓌠𓌡𓌢𓌣𓌤𓌥𓌦𓌧𓌨𓌩𓌪𓌫𓌬𓌭𓌮𓌯𓌰𓌱𓌲𓌳𓌴𓌵𓌶𓌷𓌸𓌹𓌺𓌻𓌼𓌽𓌾𓌿𓍀𓍁𓍂𓍃𓍄𓍅𓍆𓍇"\
+"𓍈𓍉𓍊𓍋𓍌𓍍𓍎𓍏𓍐𓍑𓍒𓍓𓍔𓍕𓍖𓍗𓍘𓍙𓍚𓍛𓍜𓍝𓍞𓍟𓍠𓍡𓍢𓍣𓍤𓍥𓍦𓍧𓍨𓍩𓍪𓍫𓍬𓍭𓍮𓍯"\
+"𓍰𓍱𓍲𓍳𓍴𓍵𓍶𓍷𓍸𓍹𓍺𓍻𓍼𓍽𓍾𓍿𓎀𓎁𓎂𓎃𓎄𓎅𓎆𓎇𓎈𓎉𓎊𓎋𓎌𓎍𓎎𓎏𓎐𓎑𓎒𓎓𓎔𓎕𓎖𓎗"\
+"𓎘𓎙𓎚𓎛𓎜𓎝𓎞𓎟𓎠𓎡𓎢𓎣𓎤𓎥𓎦𓎧𓎨𓎩𓎪𓎫𓎬𓎭𓎮𓎯𓎰𓎱𓎲𓎳𓎴𓎵𓎶𓎷𓎸𓎹𓎺𓎻𓎼𓎽𓎾𓎿"\
+"𓏀𓏁𓏂𓏃𓏄𓏅𓏆𓏇𓏈𓏉𓏊𓏋𓏌𓏍𓏎𓏏𓏐𓏑𓏒𓏓𓏔𓏕𓏖𓏗𓏘𓏙𓏚𓏛𓏜𓏝𓏞𓏟𓏠𓏡𓏢𓏣𓏤𓏥𓏦𓏧"\
+"𓏨𓏩𓏪𓏫𓏬𓏭𓏮𓏯𓏰𓏱𓏲𓏳𓏴𓏵𓏶𓏷𓏸𓏹𓏺𓏻𓏼𓏽𓏾𓏿𓐀𓐁𓐂𓐃𓐄𓐅𓐆𓐇𓐈𓐉𓐊𓐋𓐌𓐍𓐎𓐏"\
+"𓐐𓐑𓐒𓐓𓐔𓐕𓐖𓐗𓐘𓐙𓐚𓐛𓐜𓐝𓐞𓐟𓐠𓐡𓐢𓐣𓐤𓐥𓐦𓐧𓐨𓐩𓐪𓐫𓐬𓐭𓐮"
+;
+#endif
+
+// musical
+#ifndef _LA_ICO_MUSICAL
+#define _LA_ICO_MUSICAL\
+"𝀀𝀁𝀂𝀃𝀄𝀅𝀆𝀇𝀈𝀉𝀊𝀋𝀌𝀍𝀎𝀏𝀐𝀑𝀒𝀓𝀔𝀕𝀖𝀗𝀘𝀙𝀚𝀛𝀜𝀝𝀞𝀟𝀠𝀡𝀢𝀣𝀤𝀥𝀦𝀧"\
+"𝀨𝀩𝀪𝀫𝀬𝀭𝀮𝀯𝀰𝀱𝀲𝀳𝀴𝀵𝀶𝀷𝀸𝀹𝀺𝀻𝀼𝀽𝀾𝀿𝁀𝁁𝁂𝁃𝁄𝁅𝁆𝁇𝁈𝁉𝁊𝁋𝁌𝁍𝁎𝁏"\
+"𝁐𝁑𝁒𝁓𝁔𝁕𝁖𝁗𝁘𝁙𝁚𝁛𝁜𝁝𝁞𝁟𝁠𝁡𝁢𝁣𝁤𝁥𝁦𝁧𝁨𝁩𝁪𝁫𝁬𝁭𝁮𝁯𝁰𝁱𝁲𝁳𝁴𝁵𝁶𝁷"\
+"𝁸𝁹𝁺𝁻𝁼𝁽𝁾𝁿𝂀𝂁𝂂𝂃𝂄𝂅𝂆𝂇𝂈𝂉𝂊𝂋𝂌𝂍𝂎𝂏𝂐𝂑𝂒𝂓𝂔𝂕𝂖𝂗𝂘𝂙𝂚𝂛𝂜𝂝𝂞𝂟"\
+"𝂠𝂡𝂢𝂣𝂤𝂥𝂦𝂧𝂨𝂩𝂪𝂫𝂬𝂭𝂮𝂯𝂰𝂱𝂲𝂳𝂴𝂵𝂶𝂷𝂸𝂹𝂺𝂻𝂼𝂽𝂾𝂿𝃀𝃁𝃂𝃃𝃄𝃅𝃆𝃇"\
+"𝃈𝃉𝃊𝃋𝃌𝃍𝃎𝃏𝃐𝃑𝃒𝃓𝃔𝃕𝃖𝃗𝃘𝃙𝃚𝃛𝃜𝃝𝃞𝃟𝃠𝃡𝃢𝃣𝃤𝃥𝃦𝃧𝃨𝃩𝃪𝃫𝃬𝃭𝃮𝃯"\
+"𝃰𝃱𝃲𝃳𝃴𝃵𝄀𝄁𝄂𝄃𝄄𝄅𝄆𝄇𝄈𝄉𝄊𝄋𝄌𝄍𝄎𝄏𝄐𝄑𝄒𝄓𝄔𝄕𝄖𝄗𝄘𝄙𝄚𝄛𝄜𝄝𝄞𝄟𝄠𝄡"\
+"𝄢𝄣𝄤𝄥𝄦𝄩𝄪𝄫𝄬𝄭𝄮𝄯𝄰𝄱𝄲𝄳𝄴𝄵𝄶𝄷𝄸𝄹𝄺𝄻𝄼𝄽𝄾𝄿𝅀𝅁𝅂𝅃𝅄𝅅𝅆𝅇𝅈𝅉𝅊𝅋"\
+"𝅌𝅍𝅎𝅏𝅐𝅑𝅒𝅓𝅔𝅕𝅖𝅗𝅘𝅙𝅚𝅛𝅜𝅝𝅗𝅥𝅘𝅥𝅘𝅥𝅮𝅘𝅥𝅯𝅘𝅥𝅰𝅘𝅥𝅱𝅘𝅧𝅨𝅩𝅥𝅲𝅥𝅦𝅪𝅫𝅬𝅮𝅯𝅰𝅱𝅲𝅭𝅳"\
+"𝅴𝅵𝅶𝅷𝅸𝅹𝅺𝅻𝅼𝅽𝅾𝅿𝆀𝆁𝆂𝆃𝆄𝆊𝆋𝆅𝆆𝆇𝆈𝆉𝆌𝆍𝆎𝆏𝆐𝆑𝆒𝆓𝆔𝆕𝆖𝆗𝆘𝆙𝆚𝆛"\
+"𝆜𝆝𝆞𝆟𝆠𝆡𝆢𝆣𝆤𝆥𝆦𝆧𝆨𝆩𝆪𝆫𝆬𝆭𝆮𝆯𝆰𝆱𝆲𝆳𝆴𝆵𝆶𝆷𝆸𝆹𝆺𝆹𝅥𝆺𝅥𝆹𝅥𝅮𝆺𝅥𝅮𝆹𝅥𝅯𝆺𝅥𝅯𝇁𝇂𝇃"\
+"𝇄𝇅𝇆𝇇𝇈𝇉𝇊𝇋𝇌𝇍𝇎𝇏𝇐𝇑𝇒𝇓𝇔𝇕𝇖𝇗𝇘𝇙𝇚𝇛𝇜𝇝𝇞𝇟𝇠𝇡𝇢𝇣𝇤𝇥𝇦𝇧𝇨𝈀𝈁𝈂"\
+"𝈃𝈄𝈅𝈆𝈇𝈈𝈉𝈊𝈋𝈌𝈍𝈎𝈏𝈐𝈑𝈒𝈓𝈔𝈕𝈖𝈗𝈘𝈙𝈚𝈛𝈜𝈝𝈞𝈟𝈠𝈡𝈢𝈣𝈤𝈥𝈦𝈧𝈨𝈩𝈪"\
+"𝈫𝈬𝈭𝈮𝈯𝈰𝈱𝈲𝈳𝈴𝈵𝈶𝈷𝈸𝈹𝈺𝈻𝈼𝈽𝈾𝈿𝉀𝉁𝉂𝉃𝉄𝉅"
+;
+#endif
+
+// mayan_num
+#ifndef _LA_ICO_MAYAN_NUM
+#define _LA_ICO_MAYAN_NUM\
+"𝋠𝋡𝋢𝋣𝋤𝋥𝋦𝋧𝋨𝋩𝋪𝋫𝋬𝋭𝋮𝋯𝋰𝋱𝋲𝋳"
+;
+#endif
+
+// taixuan
+#ifndef _LA_ICO_TAIXUAN
+#define _LA_ICO_TAIXUAN\
+"𝌀𝌁𝌂𝌃𝌄𝌅𝌆𝌇𝌈𝌉𝌊𝌋𝌌𝌍𝌎𝌏𝌐𝌑𝌒𝌓𝌔𝌕𝌖𝌗𝌘𝌙𝌚𝌛𝌜𝌝𝌞𝌟𝌠𝌡𝌢𝌣𝌤𝌥𝌦𝌧"\
+"𝌨𝌩𝌪𝌫𝌬𝌭𝌮𝌯𝌰𝌱𝌲𝌳𝌴𝌵𝌶𝌷𝌸𝌹𝌺𝌻𝌼𝌽𝌾𝌿𝍀𝍁𝍂𝍃𝍄𝍅𝍆𝍇𝍈𝍉𝍊𝍋𝍌𝍍𝍎𝍏"\
+"𝍐𝍑𝍒𝍓𝍔𝍕𝍖"
+;
+#endif
+
+// rod
+#ifndef _LA_ICO_ROD
+#define _LA_ICO_ROD\
+"𝍠𝍡𝍢𝍣𝍤𝍥𝍦𝍧𝍨𝍩𝍪𝍫𝍬𝍭𝍮𝍯𝍰𝍱𝍲𝍳𝍴𝍵𝍶𝍷𝍸"
+;
+#endif
+
+// enclosed
+#ifndef _LA_ICO_ENCLOSED
+#define _LA_ICO_ENCLOSED\
+"🄀🄁🄂🄃🄄🄅🄆🄇🄈🄉🄊🄋🄌🄐🄑🄒🄓🄔🄕🄖🄗🄘🄙🄚🄛🄜🄝🄞🄟🄠🄡🄢🄣🄤🄥🄦🄧🄨🄩🄪"\
+"🄫🄬🄭🄮🄯🄰🄱🄲🄳🄴🄵🄶🄷🄸🄹🄺🄻🄼🄽🄾🄿🅀🅁🅂🅃🅄🅅🅆🅇🅈🅉🅊🅋🅌🅍🅎🅏🅐🅑🅒"\
+"🅓🅔🅕🅖🅗🅘🅙🅚🅛🅜🅝🅞🅟🅠🅡🅢🅣🅤🅥🅦🅧🅨🅩🅪🅫🅬🅰🅱🅲🅳🅴🅵🅶🅷🅸🅹🅺🅻🅼🅽"\
+"🅾🅿🆀🆁🆂🆃🆄🆅🆆🆇🆈🆉🆊🆋🆌🆍🆎🆏🆐🆑🆒🆓🆔🆕🆖🆗🆘🆙🆚🆛🆜🆝🆞🆟🆠🆡🆢🆣🆤🆥"\
+"🆦🆧🆨🆩🆪🆫🆬🇦🇧🇨🇩🇪🇫🇬🇭🇮🇯🇰🇱🇲🇳🇴🇵🇶🇷🇸🇹🇺🇻🇼🇽🇾🇿🈁🈂🈚🈯🈲🈳🈴"\
+"🈵🈶🈷🈸🈹🈺🉐🉑"
+;
+#endif
+
+// emo
+#ifndef _LA_ICO_EMO
+#define _LA_ICO_EMO\
+"😀😁😂😃😄😅😆😇😈😉😊😋😌😍😎😏😐😑😒😓😔😕😖😗😘😙😚😛😜😝😞😟😠😡😢😣😤😥😦😧"\
+"😨😩😪😫😬😭😮😯😰😱😲😳😴😵😶😷😸😹😺😻😼😽😾😿🙀🙁🙂🙃🙄🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏"
+#endif
+
+// transport
+#ifndef _LA_ICO_TRANSPORT
+#define _LA_ICO_TRANSPORT\
+"🚀🚁🚂🚃🚄🚅🚆🚇🚈🚉🚊🚋🚌🚍🚎🚏🚐🚑🚒🚓🚔🚕🚖🚗🚘🚙🚚🚛🚜🚝🚞🚟🚠🚡🚢🚣🚤🚥🚦🚧"\
+"🚨🚩🚪🚫🚬🚭🚮🚯🚰🚱🚲🚳🚴🚵🚶🚷🚸🚹🚺🚻🚼🚽🚾🚿🛀🛁🛂🛃🛄🛅🛆🛇🛈🛉🛊🛋🛌🛍🛎🛏"\
+"🛐🛑🛒🛓🛔🛕🛖🛗🛝🛞🛟🛠🛡🛢🛣🛤🛥🛦🛧🛨🛩🛪🛫🛬🛰🛱🛲🛳🛴🛵🛶🛷🛸🛹🛺🛻🛼"
+;
+#endif
+
+// alchemical
+#ifndef _LA_ICO_ALCHEMICAL
+#define _LA_ICO_ALCHEMICAL\
+"🜀🜁🜂🜃🜄🜅🜆🜇🜈🜉🜊🜋🜌🜍🜎🜏🜐🜑🜒🜓🜔🜕🜖🜗🜘🜙🜚🜛🜜🜝🜞🜟🜠🜡🜢🜣🜤🜥🜦🜧"\
+"🜨🜩🜪🜫🜬🜭🜮🜯🜰🜱🜲🜳🜴🜵🜶🜷🜸🜹🜺🜻🜼🜽🜾🜿🝀🝁🝂🝃🝄🝅🝆🝇🝈🝉🝊🝋🝌🝍🝎🝏"\
+"🝐🝑🝒🝓🝔🝕🝖🝗🝘🝙🝚🝛🝜🝝🝞🝟🝠🝡🝢🝣🝤🝥🝦🝧🝨🝩🝪🝫🝬🝭🝮🝯🝰🝱🝲🝳"
+;
+#endif
+
+// pic
+#ifndef _LA_ICO_PIC
+#define _LA_ICO_PIC\
+"🤌🤍🤎🤏🤐🤑🤒🤓🤔🤕🤖🤗🤘🤙🤚🤛🤜🤝🤞🤟🤠🤡🤢🤣🤤🤥🤦🤧🤨🤩🤪🤫🤬🤭🤮🤯🤰🤱🤲🤳"\
+"🤴🤵🤶🤷🤸🤹🤺🤻🤼🤽🤾🤿🥀🥁🥂🥃🥄🥅🥆🥇🥈🥉🥊🥋🥌🥍🥎🥏🥐🥑🥒🥓🥔🥕🥖🥗🥘🥙🥚🥛"\
+"🥜🥝🥞🥟🥠🥡🥢🥣🥤🥥🥦🥧🥨🥩🥪🥫🥬🥭🥮🥯🥰🥱🥲🥳🥴🥵🥶🥷🥸🥹🥺🥻🥼🥽🥾🥿🦀🦁🦂🦃"\
+"🦄🦅🦆🦇🦈🦉🦊🦋🦌🦍🦎🦏🦐🦑🦒🦓🦔🦕🦖🦗🦘🦙🦚🦛🦜🦝🦞🦟🦠🦡🦢🦣🦤🦥🦦🦧🦨🦩🦪🦫"\
+"🦬🦭🦮🦯🦰🦱🦲🦳🦴🦵🦶🦷🦸🦹🦺🦻🦼🦽🦾🦿🧀🧁🧂🧃🧄🧅🧆🧇🧈🧉🧊🧋🧌🧍🧎🧏🧐🧑🧒🧓"\
+"🧔🧕🧖🧗🧘🧙🧚🧛🧜🧝🧞🧟🧠🧡🧢🧣🧤🧥🧦🧧🧨🧩🧪🧫🧬🧭🧮🧯🧰🧱🧲🧳🧴🧵🧶🧷🧸🧹🧺🧻"\
+"🧼🧽🧾🧿🩰🩱🩲🩳🩴🩸🩹🩺🩻🩼🪀🪁🪂🪃🪄🪅🪆🪐🪑🪒🪓🪔🪕🪖🪗🪘🪙🪚🪛🪜🪝🪞🪟🪠🪡🪢"\
+"🪣🪤🪥🪦🪧🪨🪩🪪🪫🪬🪰🪱🪲🪳🪴🪵🪶🪷🪸🪹🪺🫀🫁🫂🫃🫄🫅🫐🫑🫒🫓🫔🫕🫖🫗🫘🫙🫠🫡🫢"\
+"🫣🫤🫥🫦🫧🫰🫱🫲🫳🫴🫵🫶"
+;
+#endif
+
+// chess
+#ifndef _LA_ICO_CHESS
+#define _LA_ICO_CHESS\
+"🨀🨁🨂🨃🨄🨅🨆🨇🨈🨉🨊🨋🨌🨍🨎🨏🨐🨑🨒🨓🨔🨕🨖🨗🨘🨙🨚🨛🨜🨝🨞🨟🨠🨡🨢🨣🨤🨥🨦🨧"\
+"🨨🨩🨪🨫🨬🨭🨮🨯🨰🨱🨲🨳🨴🨵🨶🨷🨸🨹🨺🨻🨼🨽🨾🨿🩀🩁🩂🩃🩄🩅🩆🩇🩈🩉🩊🩋🩌🩍🩎🩏"\
+"🩐🩑🩒🩓🩠🩡🩢🩣🩤🩥🩦🩧🩨🩩🩪🩫🩬🩭"
+;
+#endif
+
+// Generated 4968 characters
+// Glyphs with no names: 0
+// 

+ 123 - 0
source/lagui/la_icon_gen.py

@@ -0,0 +1,123 @@
+import fontforge
+import unicodedata
+
+
+gen=open("la_icon.h", "w")
+
+written=0;
+no_name=[]
+categories=[]
+f=[]
+
+gen.write("#pragma once\n\n")
+
+def find_glyph(unicode):
+    glyph=None
+    for i in range(len(f)):
+        try:
+            glyph=f[i][unicode]
+        except:
+            glyph=None
+        if glyph:
+            break
+    return glyph
+
+groups=[
+[73, "currency", []],#Currency Symbols]
+[77, "arrows", []],#Arrows]
+[78, "dingbats", []],#Mathematical Operators]
+[79, "tech", []],#Miscellaneous Technical]
+#[83, "box", []],#Box Drawing]
+#[84, "block", []],#Block Elements]
+[85, "geom", []],#Geometric Shapes]
+[86, "misc", []],#Miscellaneous Symbols]
+[87, "dingbats", []],#Dingbats]
+[88, "math", []],#Miscellaneous Mathematical Symbols-A]
+[89, "arrows", []],#Supplemental Arrows-A]
+[90, "braille", []],#Braille Patterns]
+[91, "arrows", []],#Supplemental Arrows-B]
+[92, "math", []],#Miscellaneous Mathematical Symbols-B]
+[93, "math", []],#Supplemental Mathematical Operators]
+[94, "misc", []],#Miscellaneous Symbols and Arrows]
+#[163, "linear_b_s", []],#Linear B Syllabary]
+#[164, "linear_b_i", []],#Linear B Ideograms]
+#[238,, []],# Cuneiform]
+#[239,, []],# Cuneiform Numbers and Punctuation]
+#[240, "edc", []],#Early Dynastic Cuneiform]
+[241, "egyptian", []],#Egyptian Hieroglyphs]
+#[242,, []],# Egyptian Hieroglyph Format Controls]
+#[243, "anatonllian", []],#Anatolian Hieroglyphs]
+#[244, "bamum", []],#Bamum Supplement]
+#[257, "duployan", []],#Duployan]
+[259, "musical", []],#Byzantine Musical Symbols]
+[260, "musical", []],#Musical Symbols]
+[261, "musical", []],#Ancient Greek Musical Notation]
+[262, "mayan_num", []],#Mayan Numerals]
+[263, "taixuan", []],#Tai Xuan Jing Symbols]
+[264, "rod", []],#Counting Rod Numerals]
+#[274, "arabic_math", []],#Arabic Mathematical Alphabetic Symbols]
+#[275,, []],# Mahjong Tiles]
+#[276,, []],# Domino Tiles]
+#[277,, []],# Playing Cards]
+[278, "enclosed", []],#Enclosed Alphanumeric Supplement]
+[279, "enclosed", []],#Enclosed Ideographic Supplement]
+[280, "misc", []],#Miscellaneous Symbols and Pictographs]
+[281, "emo", []],#Emoticons]
+[282, "dingbats", []],#Ornamental Dingbats]
+[283, "transport", []],#Transport and Map Symbols]
+[284, "alchemical", []],#Alchemical Symbols]
+[285, "geom", []],#Geometric Shapes Extended]
+[286, "arrows", []],#Supplemental Arrows-C]
+[287, "pic", []],#Supplemental Symbols and Pictographs]
+[288, "chess", []],#Chess Symbols]
+[289, "pic", []],#Symbols and Pictographs Extended-A]
+#[290, "", []],#legact computing]
+]
+
+f.append(fontforge.open("/home/yiming/.local/share/fonts/NotoSansSymbols-Regular.ttf"))
+f.append(fontforge.open("/home/yiming/.local/share/fonts/NotoSansSymbols2-Regular.ttf"))
+f.append(fontforge.open("/home/yiming/.local/share/fonts/NotoEmoji-Regular.ttf"))
+f.append(fontforge.open("/home/yiming/.local/share/fonts/NotoMusic-Regular.ttf"))
+f.append(fontforge.open("/home/yiming/.local/share/fonts/NotoSansEgyptianHieroglyphs-Regular.ttf"))
+
+for i in range(len(groups)):
+    begin=fontforge.UnicodeBlockStartFromLib(groups[i][0])
+    end=fontforge.UnicodeBlockEndFromLib(groups[i][0])+1
+    for c in range(begin,end):
+        glyph=find_glyph(c)
+        if glyph is not None:
+            groups[i][2].append(glyph)
+
+for i in range(len(groups)):
+    for j in range(i+1,len(groups)):
+        if groups[j][1]!=groups[i][1] or len(groups[j][2])==0:
+            continue;
+        groups[i][2].extend(groups[j][2])
+        groups[j][2]=[]
+
+irow=0;
+row=40;
+
+for i in range(len(groups)):
+    irow=0;
+    if len(groups[i][2])==0:
+        continue;
+    gen.write("// "+groups[i][1]+"\n#ifndef _LA_ICO_"+groups[i][1].upper()+"\n#define _LA_ICO_"+groups[i][1].upper()+"\\\n")
+    for c in groups[i][2]:
+        if (irow%row==0):
+            gen.write("\"")
+        gen.write(str(chr(c.unicode)));
+        written+=1;
+        irow+=1
+        if (irow%row==0):
+            gen.write("\"\\\n")
+    if (irow%row!=0):
+            gen.write("\"\n")
+    gen.write(";\n#endif\n\n")
+
+gen.write("// Generated %s characters\n"%(written));
+gen.write("// Glyphs with no names: %d\n// "%len(no_name));
+for n in no_name:
+    gen.write(chr(n));
+
+gen.close()

+ 1715 - 0
source/lagui/la_interface.h

@@ -0,0 +1,1715 @@
+#pragma once
+
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <X11/Xlocale.h>
+#include <X11/XKBlib.h>
+
+#include <GL/glew.h>
+//#include <GL/glxew.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <GL/glext.h>
+#include <GL/glu.h>
+
+#include "la_5.h"
+#include "la_data.h"
+//#include "llvm-c/Analysis.h"
+//#include "llvm-c/BitWriter.h"
+//#include "llvm-c/Core.h"
+//#include "llvm-c/ExecutionEngine.h"
+//#include "llvm-c/Target.h"
+//#include <Windows.h>
+
+#define LA_VERSION_MAIN 5
+#define LA_VERSION_SUB 0
+#define LA_VERSION_MINOR 0
+
+#define LA_UDF_CAPABILITY_MAIN 5
+#define LA_UDF_CAPABILITY_SUB 0
+#define LA_UDF_CAPABILITY_MINOR 0
+
+#define LA_ACTUATOR_CAPABILITY_MAIN 5
+#define LA_ACTUATOR_CAPABILITY_SUB 0
+#define LA_ACTUATOR_CAPABILITY_MINOR 0
+
+#define LA_NODE_MAIN_MODULE_NAME "LA_NODE_MAIN_MODULE"
+
+#define LA_GUI_WNDCLASS_NAME "LA_WINDOW_CLASS"
+#define LA_ARROW 1
+#define LA_CROSS 2
+#define LA_LEFT_RIGHT 3
+#define LA_UP_AND_DOWN 4
+#define LA_HAND 5
+#define LA_MOVE 6
+
+#define EVT_WND_MOVE -1
+#define EVT_WND_SIZE_BEGIN -2
+#define EVT_WND_SIZE_FINISH -3
+#define EVT_WND_SIZE -4
+#define EVT_WND_SHOW -5
+
+#define EVT_FEEDBACK 8192
+
+#define LA_KEYBOARD_EVENT (1<<0)
+#define LA_MOUSE_EVENT    (1<<1)
+#define LA_STATE_MOVE     (1<<2)
+#define LA_STATE_DOWN     (1<<3)
+#define LA_STATE_UP       (1<<4)
+
+#define LA_TIME_EVENT     (1<<5)
+#define LA_TIME_IDLE      (LA_TIME_EVENT|(1<<6))
+#define LA_TIME_DELAY     (LA_TIME_EVENT|(1<<7))
+
+#define LA_KEY_MOUSE_LEFT   (1<<8)
+#define LA_KEY_MOUSE_MIDDLE (1<<9)
+#define LA_KEY_MOUSE_RIGHT  (1<<10)
+#define LA_KEY_MOUSE_SCROLL (1<<11)
+
+#define LA_KEY_BACKSPACE (1<<12)
+#define LA_KEY_ESCAPE    (1<<13)
+#define LA_KEY_ENTER     (1<<14)
+#define LA_INPUT         (1<<15)
+#define LA_KEY_ARRLEFT   (1<<16)
+#define LA_KEY_ARRRIGHT  (1<<17)
+#define LA_KEY_ARRUP     (1<<18)
+#define LA_KEY_ARRDOWN   (1<<19)
+#define LA_KEY_SHIFT     (1<<20)
+#define LA_KEY_CTRL      (1<<21)
+#define LA_KEY_ALT       (1<<22)
+#define LA_KEY_DELETE    (1<<23)
+#define LA_KEY_TAB       (1<<24)
+
+#define LA_KEY_SPECIALS (LA_KEY_CTRL|LA_KEY_SHIFT|LA_KEY_ALT)
+
+#define LA_MOUSEMOVE (LA_MOUSE_EVENT | LA_STATE_MOVE)
+#define LA_EMPTY LA_MOUSEMOVE
+
+#define LA_MOUSEDOWN (LA_MOUSE_EVENT | LA_STATE_DOWN)
+#define LA_MOUSEUP (LA_MOUSE_EVENT | LA_STATE_UP)
+#define LA_WHEEL (LA_MOUSE_EVENT | LA_KEY_MOUSE_SCROLL)
+
+#define LA_L_MOUSE_DOWN (LA_MOUSE_EVENT | LA_STATE_DOWN | LA_KEY_MOUSE_LEFT)
+#define LA_L_MOUSE_UP (LA_MOUSE_EVENT | LA_STATE_UP | LA_KEY_MOUSE_LEFT)
+#define LA_M_MOUSE_DOWN (LA_MOUSE_EVENT | LA_STATE_DOWN | LA_KEY_MOUSE_MIDDLE)
+#define LA_M_MOUSE_UP (LA_MOUSE_EVENT | LA_STATE_UP | LA_KEY_MOUSE_MIDDLE)
+#define LA_R_MOUSE_DOWN (LA_MOUSE_EVENT | LA_STATE_DOWN | LA_KEY_MOUSE_RIGHT)
+#define LA_R_MOUSE_UP (LA_MOUSE_EVENT | LA_STATE_UP | LA_KEY_MOUSE_RIGHT)
+#define LA_MOUSE_WHEEL_DOWN (LA_MOUSE_EVENT | LA_STATE_DOWN | LA_KEY_MOUSE_SCROLL)
+#define LA_MOUSE_WHEEL_UP (LA_MOUSE_EVENT | LA_STATE_UP | LA_KEY_MOUSE_SCROLL)
+#define LA_KEY_DOWN (LA_KEYBOARD_EVENT | LA_STATE_DOWN)
+#define LA_KEY_UP (LA_KEYBOARD_EVENT | LA_STATE_UP)
+
+#define LA_LEFT_DOWN (LA_KEYBOARD_EVENT | LA_KEY_ARRLEFT | LA_STATE_DOWN)
+#define LA_RIGHT_DOWN (LA_KEYBOARD_EVENT | LA_KEY_ARRRIGHT | LA_STATE_DOWN)
+#define LA_UP_DOWN (LA_KEYBOARD_EVENT | LA_KEY_ARRUP | LA_STATE_DOWN)
+#define LA_DOWN_DOWN (LA_KEYBOARD_EVENT | LA_KEY_ARRDOWN | LA_STATE_DOWN)
+#define LA_LEFT_UP (LA_KEYBOARD_EVENT | LA_KEY_ARRLEFT | LA_STATE_UP)
+#define LA_RIGHT_UP (LA_KEYBOARD_EVENT | LA_KEY_ARRRIGHT | LA_STATE_UP)
+#define LA_UP_UP (LA_KEYBOARD_EVENT | LA_KEY_ARRUP | LA_STATE_UP)
+#define LA_DOWN_UP (LA_KEYBOARD_EVENT | LA_KEY_ARRDOWN | LA_STATE_UP)
+#define LA_BACKSPACE_DOWN (LA_KEYBOARD_EVENT | LA_KEY_BACKSPACE | LA_STATE_DOWN)
+#define LA_BACKSPACE_UP (LA_KEYBOARD_EVENT | LA_KEY_BACKSPACE | LA_STATE_UP)
+#define LA_ESCAPE_DOWN (LA_KEYBOARD_EVENT | LA_KEY_ESCAPE | LA_STATE_DOWN)
+#define LA_ESCAPE_UP (LA_KEYBOARD_EVENT | LA_KEY_ESCAPE | LA_STATE_UP)
+#define LA_ENTER_DOWN (LA_KEYBOARD_EVENT | LA_KEY_ENTER | LA_STATE_DOWN)
+#define LA_ENTER_UP (LA_KEYBOARD_EVENT | LA_KEY_ENTER | LA_STATE_UP)
+
+#define LA_ONLY_BITS_AND(orig, yours) \
+    ((orig & yours) == yours)
+
+NEED_STRUCTURE(laTunnel);
+NEED_STRUCTURE(laUiList);
+NEED_STRUCTURE(laUiItem);
+NEED_STRUCTURE(laColumn);
+
+typedef void (*laUiDrawFunc)(void *, int);               //Instance,Theme
+typedef void (*laPanelDrawFunc)(void *, void *, void *); //Window,Instance,Theme
+//typedef void(*laUiDefineFunc)(laUiList*,laPropPack*,laPropPack*,laColumn*);//uil,collection inst+"This" inst,actuator inst,Extra column list.
+typedef void (*laOperatorArgumentParserFunc)(laStringSplitor *, uint32_t *, char *); //icon id,display string buf
+typedef int (*laUiGetHeightFunc)(laUiItem *);
+typedef int (*laUiGetMinWidthFunc)(laUiItem *);
+typedef int (*laUiConditionFunc)(laPropPack *); //maybe inst+actuator,replaceInst
+typedef void (*laUiDestroyFunc)(laUiItem *);
+typedef void (*laUiInitFunc)(laUiItem *);
+typedef void (*laUiRefreshFunc)(laUiItem *);
+typedef void (*laLayoutBkgDrawFunc)(void *, void *l);
+
+STRUCTURE(laEvent){
+    laListItem Item;
+
+    int Type;
+    int state;
+    int x, y;
+    int key;
+    int SpecialKeyBit;
+
+    int p1, p2;
+
+    uint32_t Input;
+
+    void *Localized;
+
+    //void* BoardcastedData;
+};
+
+NEED_STRUCTURE(laWindow)
+NEED_STRUCTURE(laRoot)
+NEED_STRUCTURE(laPanel)
+NEED_STRUCTURE(laUiItem)
+NEED_STRUCTURE(laUiList)
+NEED_STRUCTURE(laAnimationAction)
+NEED_STRUCTURE(laUiDescriptor)
+NEED_STRUCTURE(laUiConditionNode)
+
+STRUCTURE(laSharedTypeItem){
+    laListItem Item;
+    char ID[64];
+    void *Pointer;
+};
+
+#define LA_ANIMATION_STOPPED 0
+#define LA_ANIMATION_PLAYING 1
+#define LA_ANIMATION_PLAYING_REVERSE 2
+
+STRUCTURE(laAnimationGlobal){
+    laListItem Item;
+
+    int PlayStatus;
+
+    int Frame;
+    int FrameBegin, FrameEnd;
+    int FrameStep;
+    int FrameRate;
+};
+
+NEED_STRUCTURE(laTranslation);
+NEED_STRUCTURE(laTheme);
+
+STRUCTURE(laKeyMapper){
+    laListItem Item;//unused;
+    laListHandle Items;
+};
+
+STRUCTURE(laLogEntry){
+    laListItem Item;
+    laSafeString* Content;
+    int Type;
+};
+
+NEED_STRUCTURE(laManagedUDF);
+
+STRUCTURE(laNodeOutSocket){
+    void* Parent;
+    void* Data;
+    laSafeString* Label;
+    int DataType;
+    int RuntimeX, RuntimeY, RuntimePX, RuntimePY;
+};
+STRUCTURE(laNodeInSocket){
+    laNodeOutSocket* Source;
+    laSafeString* Label;
+    int DataType; int ColorId;
+    int RuntimeX, RuntimeY, RuntimePX, RuntimePY;
+};
+
+STRUCTURE(LA){
+    laListItem Hyper;
+
+    laListHandle Logs;
+    laListHandle Controllers;
+
+    laListHandle Windows;
+
+    real IdleStart, DelayStart;
+    int DelayTriggered;
+    int IdleTriggered;
+    int ReTriggerOperators;
+    laPanel* DockingPanel;
+
+    char *InputBuf; int InputBufNext, InputBufMax;
+    int32_t *InputBufU; int InputBufUNext, InputBufUMax;
+    Atom MsgDelWindow;
+    Atom bufid;
+    Atom fmtid;
+    Atom propid;
+    Atom incrid;
+	Atom targets_atom;
+	Atom text_atom;
+	Atom UTF8;
+	Atom selection;
+    laSafeString* CopyPending;
+
+    Display* dpy;
+    XVisualInfo* xvi;
+    GLXFBConfig BestFBC;
+    GLXContext glc;
+    Colormap cmap;
+    XIM im;
+    XIC ic;
+
+    laWindow *CurrentWindow;
+    laPanel *CurrentPanel;
+
+    int SpecialKeyStates;
+    laKeyMapper KeyMap;
+
+    laHash256 OperatorTypeHash;
+
+    laPropContainer *GeneralIntSub;
+    laPropContainer *GeneralFloatSub;
+    laPropContainer *GeneralEnumSub;
+    laPropContainer *GeneralIntArraySub;
+    laPropContainer *GeneralFloatArraySub;
+    laPropContainer *GeneralEnumArraySub;
+    laPropContainer *GeneralStringSub;
+    laPropContainer *GeneralOperatorSub;
+    laPropContainer *GeneralCollectionSub;
+    laPropContainer *GeneralRawSub;
+
+    laPropContainer *ContainerInt;
+    laPropContainer *ContainerFloat;
+    laPropContainer *ContainerEnum;
+    laPropContainer *ContainerString;
+    laPropContainer *ContainerOperator;
+    laPropContainer *ContainerCollection;
+
+    laListHandle PropContainers;
+    laRoot DataRoot;
+    laPanel *PropMatcherContextP;
+
+    laAnimationGlobal Animation;
+
+    laTheme*     CurrentTheme;
+    laListHandle Themes;
+    laListHandle UiTypes;
+    
+    laListHandle PanelTemplates;
+    laListHandle View2DTemplates;
+
+    laHash256 GlobalMemPool;
+    int ByteCount;
+    int TotalByteCount;
+
+    laHash16M DBInst2;
+    laHash16M DBInst1;
+    laHash16M PtrSync;
+    laListHandle PtrSyncCommandList;
+    laListHandle PostReadNodes;
+    laListHandle RenewHyper2s;
+    laListHandle SharedTypePointerSync;
+
+    laListHandle ResourceFolders;
+    laListHandle ResourceRegistries;
+    laListHandle ManagedUDFs;
+    laListHandle ManagedSaveProps;
+    laManagedUDF* DummyManageUDF;
+    int          ManagerDefaultView;
+
+    laListHandle DBInstPendingAcquireDBP;
+    laListHandle DBInstPendingAcquireDiffCMD;
+
+    laListHandle DiffTouched;
+    laListHandle Differences;
+    laDiff* HeadDifference;
+    laDBInst RootDBInst;
+    laListHandle DBRecordedProps;
+    laHash65536* DBInstLink;
+
+    real FontSize;
+    real MarginSize;
+    int UiRowHeight;
+    int ScaledUiRowHeight;
+    real UiScale;
+    void *ToPanel;
+
+    int NextX, NextY, NextW, NextH;
+    laNodeInSocket tNodeIn;
+    laNodeOutSocket tNodeOut;
+
+
+    laAuthorInfo Author;
+    laListHandle ExternalAuthors;
+
+    laSafeString *WorkingDirectory;
+
+    //pthread_spinlock_t csNotifier;
+    laListHandle ThreadNotifiers;
+
+    //preference:
+
+    //color
+    int ColorAccessCorrectGamma;
+    real Gamma;
+    int NextWireColor, WireColorSlices;
+    real WireThickness;
+    real WireSaggyness;
+    real* WireColorCache;
+
+    //user interactions:
+    int TopFramerate;
+    int ValuatorThreshold;
+    int ScrollingSpeed;
+    int TooltipCloseDistance;
+    real ZoomSpeed2D;
+    real IdleTime;
+    real DelayTime;
+
+    //translations:
+    laTranslation Translation;
+
+    //display:
+    real FloatingAlpha;
+    int SolidShadowLength;
+    int TrackShadowLength;
+    int EnableAnimation;
+    real AnimationSpeed;
+    real PanelAnimationSpeed;
+    int PanelMultisample;
+    real LastFrameTime;
+    real TimeAccum;
+    
+    //animation:
+    int DefaultKeyFrameMode;
+
+    //laThemeColor *ConditionStackColors[6];
+
+    laUDFContentNode TEST_Link;
+
+    laListHandle MediaFiles;
+
+    laHash256 RootNodes;
+    //LLVMContextRef llvmContext;
+    //LLVMModuleRef llvmModule;
+
+    //pthread_spinlock_t csMediaPlay;
+
+    int example_int;
+    laSafeString* example_string;
+};
+
+#define LA_KM_SEL_UI_EXTRA 1
+#define LA_KM_SEL_PANEL 2
+
+STRUCTURE(laKeyMapItem){
+    laListItem Item;
+
+    int SpecialKeyBits;
+    int EventType;
+    int Key;
+
+    char SelectBase;
+
+    laPropPack Base;
+    laPropPack Action;
+
+    laSafeString *Operation;
+
+    laSafeString *Instructions;
+};
+
+NEED_STRUCTURE(laLayout);
+NEED_STRUCTURE(laBlock);
+NEED_STRUCTURE(laPanel);
+NEED_STRUCTURE(laUiItem);
+STRUCTURE(laWindow){
+    laListItem Item;
+
+    Window* win;
+    GLXContext glc;
+
+    int X;
+    int Y;
+    int W;
+    int H;
+    int CW;
+    int CH;
+
+    laPropPack PP;
+    laPropStep FakePS;
+
+    laSafeString *Title;
+    int Activated;
+    int Shown;
+    int IsDocking;
+    laWindow* DockingFrom;
+
+    laListHandle EventList;
+    laSafeString *OperatorHints;
+
+    laListHandle Layouts;
+    laLayout *CurrentLayout;
+    laBlock *MaximizedBlock;
+    laPanel *MaximizedUiPanel;
+    laUiItem *MaximizedUi;
+
+    laListHandle Panels;
+    laListHandle FadingPanels;
+
+    laListHandle Operators;
+    laListHandle PendingOperators;
+
+    laUiDrawFunc Draw;
+};
+
+STRUCTURE(laBlock){
+    int X, Y, W, H;
+    laBlock *B1;
+    laBlock *B2;
+    laBlock *parent;
+    laPanel *CurrentPanel;
+    laListHandle Panels;
+    int Vertical;
+    int Folded;
+    real SplitRatio; // From Left/Top;
+    laPropPack PP;
+    laPropPack FakePS;
+    int OnButton;
+};
+
+#define LA_BLOCK_DROP_LOCATION_L 1
+#define LA_BLOCK_DROP_LOCATION_R 2
+#define LA_BLOCK_DROP_LOCATION_U 3
+#define LA_BLOCK_DROP_LOCATION_B 4
+
+STRUCTURE(laLayout){
+    laListItem Item;
+
+    laBlock *OperatingBlock;
+    laBlock *FirstBlock;
+    laBlock *MovingBlock;
+    int      IsMoving;
+
+    laPanel *ClickedPanel;
+    laBlock *DropToBlock;
+    laBlock *OnBlockSeperator;
+    char DropLocation;
+
+    laSafeString *ID;
+
+    laLayoutBkgDrawFunc Draw;
+};
+
+STRUCTURE(laUiList){
+    laListItem Item;
+    int L, R, U, B;
+    int TL, TR, TU, TB;
+    real PanX, PanY; //Pan Up/Left Is Positive
+    laListHandle UiItems;
+    laListHandle Columns;
+    laListHandle *ShareColumns;
+    laSafeString *TabName;
+    char *Instance;
+    short HeightCoeff;
+    char ScrollerShownV;
+    char ScrollerShownH;
+    uint32_t IconID;
+    int AllowScale;
+    real Scale; real SaveScale;
+};
+
+STRUCTURE(laUiListRecord){
+    laListItem Item;
+    laUiList* uil;
+    laUiItem* pui;
+};
+
+STRUCTURE(laColumn){
+    laListItem Item;
+    real PreWidth;
+    real SP;
+    int IL, IR;
+    laColumn *Top;
+    int MaxW;
+    int B;
+    laColumn *LS, *RS;
+    laColumn *CopyRef;
+};
+
+STRUCTURE(laUiListDraw){
+    laListHandle Items;
+    laListHandle SocketRecord;
+    laUiList*    WiresContainer;
+};
+
+STRUCTURE(laUiListDrawItem){
+    laListItem Item;
+    laUiList *Target;
+    int L, R, U, B, XP, YP, DifX, DifY;
+    int ExtraPanX;
+    real Scale;
+};
+
+STRUCTURE(laBoxedTheme){
+    laListItem Item;
+    laSafeString *Name;
+
+    real NormalY, Normal[4], Inactive[4];
+    real ActiveY, Active[4];
+    real BorderY, Border[4];
+
+    real TextY, Text[4];
+    real TextActiveY, TextActive[4], TextInactive[4];
+    real Alpha;
+
+    int TextAlign;
+
+    real Margins[4]; 
+    real Paddings[4];
+
+    //Don't change order
+    int LM, RM, TM, BM; 
+    int LP, RP, TP, BP;
+
+    laBoxedTheme **BackRef;
+    laTheme* Parent;
+};
+
+STRUCTURE(laSocketRecord){
+    laListItem Item;
+    laNodeInSocket* In;
+    laNodeOutSocket* Out;
+};
+
+extern laPropContainer* LA_PC_SOCKET_IN;
+extern laPropContainer* LA_PC_SOCKET_OUT;
+
+#define LA_UI_NORMAL  0
+#define LA_UI_ACTIVE  (1<<0)
+#define LA_UI_EDITING  (1<<1)
+#define LA_UI_DISABLED (1<<8)
+
+#define LA_BT_NORMAL LA_UI_NORMAL
+#define LA_BT_ACTIVE LA_UI_ACTIVE
+#define LA_BT_BORDER (1<<6)
+#define LA_BT_TEXT   (1<<7)
+#define LA_BT_TEXT_NORMAL (LA_BT_TEXT|LA_UI_NORMAL)
+#define LA_BT_TEXT_ACTIVE (LA_BT_TEXT|LA_UI_ACTIVE)
+#define LA_BT_DISABLED LA_UI_DISABLED
+#define LA_BT_VERTEX (1<<8)
+#define LA_BT_EDGE   (1<<9)
+#define LA_BT_FACE   (1<<10)
+#define LA_BT_SELECTED (1<<11)
+#define LA_BT_SVERTEX (LA_BT_VERTEX|LA_BT_SELECTED)
+#define LA_BT_SEDGE   (LA_BT_EDGE|LA_BT_SELECTED)
+#define LA_BT_SFACE   (LA_BT_FACE|LA_BT_SELECTED)
+
+#define LA_UI_TAG_IS_OFFSCREEN  (1<<0)
+#define LA_UI_TAG_CAVANS_SCALED (1<<1)
+#define LA_UI_TAG_NEED_REBUILD  (LA_UI_TAG_IS_OFFSCREEN | LA_UI_TAG_CAVANS_SCALED)
+#define LA_UI_TAG_SCISSOR       (1<<2)
+
+STRUCTURE(laTheme){
+    laListItem Item;
+    laSafeString *Name;
+    laSafeString *Author;
+    laListHandle Colors;
+    laListHandle BoxedThemes;
+    int abc;
+    //
+    real ColorBkg[4];
+    real Color[4];
+    real AccentColor[4];
+    real SelectionColor[4];
+    real CursorColor[4];
+    real InactiveMix;
+    real InactiveSaturation;
+    real CursorAlpha;
+    real SelectionAlpha;
+
+    real WireSaturation;
+    real WireTransparency;
+    real WireBrightness;
+
+    real VertexColor[4];
+    real EdgeColor[4];
+    real SVertexColor[4];
+    real SEdgeColor[4];
+    real SFaceColor[4];
+    real EdgeBrightness, EdgeTransparency;
+    real VertexBrightness, VertexTransparency;
+    real SelectedVertexTransparency;
+    real SelectedEdgeTransparency;
+    real SelectedFaceTransparency;
+};
+
+NEED_STRUCTURE(laOperatorType);
+
+STRUCTURE(laUiType){
+    laListItem Item;
+
+    const char *Identifier;
+
+    int ForType;
+    const char *TargetSub;
+
+    //laPropStep      FakePs;
+    laSubProp* FakeProp;
+    laPropContainer* ExtraProps;
+
+    laBoxedTheme **Theme;
+    laUiDrawFunc Draw;
+    const char *OperatorID;
+    laOperatorType *OperatorType;
+
+    laUiGetMinWidthFunc GetMinWidth;
+    laUiGetHeightFunc GetHeight;
+
+    laUiDestroyFunc Destroy;
+    laUiInitFunc Init;
+
+    laKeyMapper KeyMapper;
+
+    int Tag;
+};
+
+NEED_STRUCTURE(laUiItem);
+STRUCTURE(laGeneralUiExtraData){
+    int LastX, LastY;
+    int TargetIndexVali;
+    real TargetIndexValf;
+    int On; //On:Modifying
+    int Dragging;
+    laStringEdit *Edit;
+    void *Ptr1;
+    void *Ptr2;
+    int HeightCoeff;
+    laUiItem* ui;
+};
+
+STRUCTURE(laMultiStringExtra){
+    laGeneralUiExtraData* general;
+    int PanX, PanY;
+};
+
+NEED_STRUCTURE(laCanvasExtra);
+
+typedef void(*laCanvasDrawFunc)(laBoxedTheme* bt, void* DataInstance, laCanvasExtra* Extra);
+
+STRUCTURE(laCanvasTemplate){
+    laListItem Item;
+    laSafeString *Identifier;
+    laCanvasDrawFunc Draw;
+    laUiDrawFunc SecondDraw;
+    laKeyMapper KeyMapper;
+    char *TargetContainerID;
+    laPropContainer *TargetContainer;
+    laPropContainer *ExtraProps;
+    laSubProp       *FakeProp;
+    //float           LimitYScale;
+    laUiInitFunc     Init;
+    laUiDestroyFunc  Destroy;
+};
+
+#define LA_SELECTION_MODE_BORDER 1
+#define LA_SELECTION_MODE_CIRCLE 2
+
+#define LA_SELECTION_STATUS_BEGINNING 0
+#define LA_SELECTION_STATUS_ENDING 1
+#define LA_SELECTION_STATUS_BEGINNING 0
+
+#define LA_EDIT_ORIGIN_CENTER 0
+#define LA_EDIT_ORIGIN_INDIVIDUAL 1
+#define LA_EDIT_ORIGIN_CURSOR 2
+
+#define LA_LINE_WIDTH_WARNING_TOO_WIDE 1
+#define LA_LINE_WIDTH_WARNING_TOO_THIN 2
+
+#define LA_CANVAS_CURSOR_CROSS 1
+#define LA_CANVAS_CURSOR_BOX   2
+#define LA_CANVAS_CURSOR_ARROW 3
+
+STRUCTURE(laCanvasExtra){
+    laListItem Item;
+    tnsOffscreen *OffScr;
+    int NoOffScreen;
+
+    laUiItem *ParentUi;
+
+    real ZoomX;
+    real ZoomY;
+
+    real PanX;
+    real PanY;
+
+    int DrawCursor;
+    real OnX, TargetX;
+    real OnY, TargetY;
+    real ClickedX;
+    real ClickedY;
+
+    int HeightCoeff;
+    //int        SnapBottom;
+
+    int ImageDrawAlpha;
+    int ImageDrawBorder;
+
+    int AdaptiveLineWidth;
+    int LineWidthWarning;
+
+    int ClearBackground;
+
+    //=========== time line display
+
+    int ShowFrameNumber;
+
+    real CursorY;
+
+    int SeletionMode;
+    int SelectStatus;
+    real BL, BR, BU, BB;
+    int EditCenter;
+
+    laListHandle PendingList; //Editing FCurve;
+    laListItemPointer *LastSelected;
+
+    int Dragging;
+    int TargetIndexVali;
+
+    //3d==========
+
+
+    tnsOffscreen *OffScrShadow;
+
+    tnsCamera *ViewingCamera; //Always create this one;
+    tnsCamera *UsingCamera;
+    tnsObject *ActiveObject;
+    int Layers[20];
+    int DisplayMode;
+
+    int ShowFloorGrid;
+    int GridSize;
+    int GridSpan;
+    int ShowAxis[3];
+
+    int LineDrawingMode;
+};
+
+NEED_STRUCTURE(laUiConditionNode);
+STRUCTURE(laConditionUiExtraData){
+    int a;
+    laUiItem *EndUi;
+    laUiItem *ElseUi;
+    laUiConditionNode *Expression;
+    //char              Remove;
+    char IsTrue;
+};
+
+STRUCTURE(laUiTemplate){
+    laListItem Item;
+    laSafeString *Title;
+    laSafeString *Identifier;
+    laUiDefineFunc          Define;
+    laUiDefineFunc          Header;
+    laPanelDetachedPropFunc PropFunc;
+    laKeyMapper KeyMap;
+};
+
+STRUCTURE(laUiItem){
+    laListItem Item;
+
+    laColumn *C;
+    int L, R, U, B;
+    int TL, TR, TU, TB;
+    int AnimationDistinguish;
+
+    int State; int Flags; // expand and even (in row control ui)
+    laPropPack ExtraPP;
+    laPropStep FakePs;
+    laGeneralUiExtraData *Extra;
+
+    //char          NoRefresh;
+    short Expand;
+    short SymbolID;
+    laPropPack PP;
+    laSafeString *Display;
+    laSafeString *ExtraInstructions;
+
+    laUiType *Type;
+    laCanvasTemplate *CanvasTemplate;
+
+    laUiList *Page; // reuse as row begin ref
+    laOperatorType *AT; //Probably share in the future;
+    laStringSplitor *Instructions;
+
+    laListHandle Subs;
+
+    laUiDefineFunc Template;
+    int TemplateContext;
+
+    laListHandle SubPanels;
+};
+
+STRUCTURE(laWidget){
+    laUiType* Type;
+    int       Flags;
+};
+
+#define LA_UI_FLAGS_TRANSPOSE (1<<0)
+#define LA_UI_FLAGS_EXPAND    (1<<1)
+#define LA_UI_FLAGS_ICON      (1<<2)
+#define LA_UI_FLAGS_CYCLE     (1<<3)
+#define LA_UI_FLAGS_NO_DECAL  (1<<4)
+#define LA_UI_FLAGS_NO_EVENT  (1<<5)
+#define LA_UI_FLAGS_NO_CONFIRM (1<<6)
+#define LA_TEXT_ALIGN_LEFT    (1<<7)
+#define LA_TEXT_ALIGN_RIGHT   (1<<8)
+#define LA_TEXT_ALIGN_CENTER  (1<<9)
+#define LA_TEXT_ALIGN_AUTO    (1<<10)
+#define LA_TEXT_USE_NEWLINE   (1<<11)
+#define LA_TEXT_LINE_WRAP     (1<<12)
+#define LA_TEXT_REVERT_Y      (1<<13)
+#define LA_TEXT_MONO          (1<<14)
+#define LA_UI_FLAGS_PREFER_BOTTOM (1<<15)
+#define LA_UI_FLAGS_NO_GAP    (1<<16)
+#define LA_UI_FLAGS_UNDERNEATH (1<<17)
+#define LA_UI_FLAGS_NO_HEIGHT (LA_UI_FLAGS_NO_GAP|LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_UNDERNEATH)
+#define LA_UI_FLAGS_NO_OVERLAY (1<<18)
+#define LA_TEXT_OVERFLOW_ARROW (1<<19)
+#define LA_UI_FLAGS_DISABLED   (1<<20)
+#define LA_UI_FLAGS_HIGHLIGHT  (1<<21)
+#define LA_UI_FLAGS_NODE_CONTAINER (1<<22)
+#define LA_UI_COLLECTION_NO_HIGHLIGHT LA_TEXT_ALIGN_LEFT
+
+#define LA_UI_FLAGS_INT_ICON  (LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_NO_EVENT|LA_UI_FLAGS_ICON)
+#define LA_UI_FLAGS_PLAIN     (LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_NO_EVENT)
+#define LA_TEXT_ALIGN (LA_TEXT_ALIGN_LEFT|LA_TEXT_ALIGN_CENTER|LA_TEXT_ALIGN_RIGHT|LA_TEXT_ALIGN_AUTO)
+
+extern laWidget* LA_WIDGET_FIXED_GROUP;
+extern laWidget* LA_WIDGET_TAB;
+extern laWidget* LA_WIDGET_COLLECTION;
+extern laWidget* LA_WIDGET_COLLECTION_ITEM;
+extern laWidget* LA_WIDGET_COLLECTION_SELECTOR;
+extern laWidget* LA_WIDGET_COLLECTION_SINGLE;
+extern laWidget* LA_WIDGET_CONDITION_TOGGLE;
+extern laWidget* LA_WIDGET_COLUMN_ADJUSTER;
+extern laWidget* LA_WIDGET_COLUMN_VIEWER;
+extern laWidget* LA_WIDGET_BUTTON;
+extern laWidget* LA_WIDGET_BUTTON_NO_CONFIRM;
+extern laWidget* LA_WIDGET_LABEL;
+extern laWidget* LA_WIDGET_INT;
+extern laWidget* LA_WIDGET_INT_PLAIN;
+extern laWidget* LA_WIDGET_INT_PLAIN_ICON;
+extern laWidget* LA_WIDGET_INT_METER;
+extern laWidget* LA_WIDGET_INT_METER_2D;
+extern laWidget* LA_WIDGET_FLOAT;
+extern laWidget* LA_WIDGET_FLOAT_PLAIN;
+extern laWidget* LA_WIDGET_FLOAT_COLOR;
+extern laWidget* LA_WIDGET_FLOAT_HCY;
+extern laWidget* LA_WIDGET_ENUM_SELECTOR;
+extern laWidget* LA_WIDGET_ENUM_SELECTOR_ICON;
+extern laWidget* LA_WIDGET_ENUM_CYCLE;
+extern laWidget* LA_WIDGET_ENUM_CYCLE_ICON;
+extern laWidget* LA_WIDGET_ENUM_ICON_PLAIN;
+extern laWidget *LA_WIDGET_ENUM_HIGHLIGHT;
+extern laWidget* LA_WIDGET_STRING;
+extern laWidget* LA_WIDGET_STRING_PLAIN;
+extern laWidget* LA_WIDGET_STRING_MULTI;
+extern laWidget *LA_WIDGET_STRING_MONO_PLAIN;
+extern laWidget* LA_WIDGET_MENU_ROOT;
+extern laWidget* LA_WIDGET_ALIGN;
+extern laWidget* LA_WIDGET_3D_VIEW;
+extern laWidget* LA_WIDGET_2D_VIEW;
+extern laWidget* LA_WIDGET_SYMBOL;
+extern laWidget *LA_WIDGET_NODE_SOCKET;
+extern laWidget *LA_WIDGET_HEIGHT_ADJUSTER;
+extern laWidget *LA_WIDGET_RAW;
+
+#define LA_CONDITION_TRUE 1
+#define LA_CONDITION_FALSE 2
+#define LA_CONDITION_GE 3
+#define LA_CONDITION_GT 4
+#define LA_CONDITION_EQ 5
+#define LA_CONDITION_LT 6
+#define LA_CONDITION_LE 7
+#define LA_CONDITION_AND 8
+#define LA_CONDITION_OR 9
+#define LA_CONDITION_NOT 10
+#define LA_CONDITION_INT 11
+#define LA_CONDITION_FLOAT 12
+#define LA_CONDITION_STRING 13
+#define LA_CONDITION_PROP 14
+
+STRUCTURE(laUiConditionNode){
+    char a;
+    int Type;
+    laUiConditionNode *Expression1; // As Int Value
+    laUiConditionNode *Expression2;
+    laUiDescriptor *Base;
+    char IsExtra;
+    int IntValue;
+    real FloatValue;
+    laSafeString *String; //used as prop path in template
+    laPropPack PP;
+};
+
+#define LA_PANEL_NORMAL 0
+#define LA_PANEL_FLOATING_PASSIVE 2
+#define LA_PANEL_FLOATING_TOP 3
+#define LA_PANEL_NO_PARENT_MENU 4
+
+#define LA_TAG_REDRAW 1
+#define LA_TAG_RECALC 2
+#define LA_TAG_ANIMATION 4
+#define LA_TAG_RECALC_SCROLLER 8
+
+#define LA_PANEL_ANIMATION_DROP_DOWN 1
+#define LA_PANEL_ANIMATION_EXPAND 2
+#define LA_PANEL_ANIMATION_DISSOVE 3
+#define LA_PANEL_ANIMATION_COLLAPSE 4
+#define LA_PANEL_ANIMATION_MINIMIZE 5
+#define LA_PANEL_ANIMATION_DESTROY 127
+
+NEED_STRUCTURE(laOperator);
+NEED_STRUCTURE(laOperator);
+
+STRUCTURE(laPanel){
+    laListItem Item;
+
+    int __SAFE__;
+
+    int X, Y, W, H;
+    int MaxW, MaxH, MinW, MinH;
+    int TX, TY, TW, TH;
+    int TitleWidth;
+
+    char AnimationMode;
+    real AnimationRatio;
+
+    //int         PanX, PanY;
+
+    int Show;
+    short Refresh;
+    unsigned int FrameDistinguish;
+
+    char BoundUi;
+    char IsMenuPanel;
+    char LaterDestroy;
+    char CloseWhenMovedOut;
+    int Mode;
+
+    int LiveEditing;
+    laUiItem *EditingUi;
+    laUiItem *FocusingUi;
+
+    void *SFPNode;
+
+    int SL, SR, ST, SB; //Snap To Edge
+
+    laSafeString *Title;
+    laUiTemplate *PanelTemplate;
+
+    laPropPack PP;
+    laPropStep FakePS;
+
+    laPropContainer* PropLinkContainer;
+    laSubProp* PropLinkFakeProp;
+    laPropPack PropLinkPP;
+    laPropStep PropLinkFakePS;
+
+    laKeyMapper KeyMap;
+
+    laPanelDrawFunc Draw;
+    laBoxedTheme **BT;
+
+    tnsOffscreen *OffScr;
+
+    laUiList UI;
+    laUiList TitleBar;
+
+    laUiList *MenuRefer;
+    laUiDefineFunc UiDefine;
+
+    laListHandle SubPanels;
+    laPanel *Parent;
+    laBlock *Block;
+
+    laOperator *ParentOperator;
+
+    u64bit Tag;
+
+    //64 Main Types are useable,with 31 subtypes avainable each.
+    //Main Type 0~63(some are occupied by LA internal)
+    //Sub Type 0~31
+    //Main (Low)  0|            1|            2|            3|...
+    //[---32bits---][---32bits---][---32bits---][---32bits---]...
+};
+
+STRUCTURE(laPanelMessage){
+    laListItem Item;
+    laSafeString *Message;
+};
+STRUCTURE(laPanelMessageList){
+    laListHandle Msg;
+};
+
+NEED_STRUCTURE(laOperator);
+
+typedef int (*laInitFunc)(laOperator *);
+typedef int (*laRefreshFunc)(laOperator *);
+typedef int (*laCheckFunc)(laPropPack *, laStringSplitor *); //this, ui->instructions amd ap->instructions
+typedef int (*laExitFunc)(laOperator *, int);         //true means Quit, false means Cancel
+typedef int (*laInvokeFunc)(laOperator *, laEvent *);
+typedef int (*laModalFunc)(laOperator *, laEvent *);
+typedef int (*laSystemFunc)(laOperator *, laEvent *);
+
+#define LA_CANCEL 0
+#define LA_PASS_ON (1<<10)
+#define LA_BLOCK (1<<11)
+#define LA_FINISH (1<<12)
+#define LA_CONFIRM (1<<13)
+
+#define LA_CANCELED 0
+//#define LA_PRE_INVOKE 16384
+#define LA_FINISHED (LA_FINISH | LA_BLOCK)
+#define LA_FINISHED_PASS (LA_FINISH | LA_PASS_ON)
+#define LA_RUNNING LA_BLOCK
+#define LA_RUNNING_PASS (LA_BLOCK | LA_PASS_ON)
+
+#define LA_OPERATOR_CALLS_SHUTOFF (LA_FINISHED|(1<<5))
+
+#define LA_EXTRA_TO_PANEL 1
+#define LA_EXTRA_CONFIRM 2
+#define LA_ACTUATOR_SYSTEM 4
+#define LA_ACTUATOR_HIDDEN 8
+
+#define LA_CONFIRM_OK (1<<10)
+#define LA_CONFIRM_CANCEL (1<<11)
+#define LA_CONFIRM_IGNORE (1<<12)
+#define LA_CONFIRM_DATA (1<<13)
+#define LA_CONFIRM_CUSTOM_STRING (1<<14)
+
+STRUCTURE(laOperatorType){
+    laListItem Item;
+
+    const char *Identifier;
+    const char *Name;
+    const char *Description;
+
+    const char *ExtraInstructions;
+
+    laInitFunc Init;
+    laExitFunc Exit;
+    laInvokeFunc Invoke;
+    laModalFunc Modal;
+    laCheckFunc Check;
+
+    uint32_t IconID;
+
+    laPropContainer* PC;
+    laUiDefineFunc UiDefine;
+
+    laOperatorArgumentParserFunc ParseArgs;
+
+    laListHandle Properties;
+
+    int ExtraMark;
+};
+
+typedef void (*laConfirmDataDestroyFunc)(void *);
+
+STRUCTURE(laConfirmData){
+    int Mode;
+    int IData;
+    real FData;
+    void *CustomData;
+    char *StrData;
+    laConfirmDataDestroyFunc Destroy;
+};
+
+STRUCTURE(laOperator){
+    laListItem Item;
+
+    int State;
+    void *Instance;
+
+    void *CustomData;
+
+    const char *ExtraInstructions;
+    laStringSplitor *ExtraInstructionsP;
+
+    laPropPack PP;
+    laPropPack *This;
+
+    laConfirmData *ConfirmData;
+    laConfirmData *NextConfirmData;
+
+    laOperator *Child;
+    laListHandle PropertyStorage;
+    laOperatorType *Type;
+
+    laPropPack *CreatedThis;
+
+    int Using;
+    int StopNow;
+
+    laPanel *ToPanel;
+    laPanel *OperatorPanel;
+    laListHandle LocalUiLists;
+
+    laSafeString* RuntimeHint;
+};
+
+#define LA_JS_MAX_AXES 32
+#define LA_JS_MAX_BUTTONS 128
+STRUCTURE(laController){
+    laListItem Item;
+    laSafeString* Name;
+    laSafeString* Path;
+    int fd; //device;
+    int NumButtons; int NumAxes;
+    int InternalType; // used to identify models and use specific props.
+    int AxisValues[LA_JS_MAX_AXES];
+    char ButtonValues[LA_JS_MAX_BUTTONS];
+};
+
+void la_InitControllers();
+void la_UpdateControllerStatus();
+void la_RegisterControllerProps();
+laPropContainer* laget_ControllerType(laController* c);
+
+void logPrintT(int Type, char* format, ...);
+void logPrint(char* format, ...);
+void logPrintNew(char* format, ...);
+
+int LA_WindowProc(Window win, int message, int wparam, int lparam);
+
+void la_RegisterMainOperators();
+void la_RegisterUiOperatorsBasic();
+void la_RegisterBuiltinOperators();
+void la_RegisterModellingOperators();
+void la_RegisterUiTypesBasic();
+void la_RegisterUiTypesViewerWidgets();
+void la_RegisterBuiltinTemplates();
+void la_RegisterWindowKeys();
+void la_RegisterGeneralProps();
+void la_RegisterInternalProps();
+
+void la_RegenerateWireColors();
+
+
+void laui_IntPropInfo(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *ExtraColumns, int context);
+void laui_FloatPropInfo(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *ExtraColumns, int context);
+
+void laui_DefaultPropDetails(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context);
+void laui_DefaultPropUiDefine(laUiList *uil, laPropPack *This, laPropPack *OperatorProps, laColumn *UNUSED, int context);
+void laui_StringPropUiDefine(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context);
+void laui_IdentifierOnly(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context);
+void laui_SubPropInfoDefault(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_SubPropSelection(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_LinkerSelectionProp(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_LinkerSelectionInstance(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_DefaultOperatorPanelTitleBar(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_ColumnItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context);
+void laui_DefaultSubWindowMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context);
+void laui_ThemeListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_Theme(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_BoxedThemeItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_PropertyContainerList(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_WindowListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_LayoutListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_PanelListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_InputSocketItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_OutputSocketItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void tnsui_GroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void tnsui_ObjectGroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void tnsui_GroupObjectItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void tnsui_MaterialItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_FileBrowserFileItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context);
+void laui_FileBrowserDiskItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context);
+void laui_LinkerPanel(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_ManagedUDFItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+void laui_ManagedUDFOps(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+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_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);
+void laui_LogItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);
+
+int OPINV_UiItem(laOperator *a, laEvent *e);
+int OPEXT_UiItem(laOperator *a, int ExitCode);
+
+int la_ArrayGetHeight(laUiItem *ui);
+int la_ValueGetHeight(laUiItem*ui);
+int la_3DViewGetHeight(laUiItem *ui);
+int la_CanvasGetHeight(laUiItem *ui);
+int la_EnumGetHeight(laUiItem *ui);
+int la_ColorPickerGetHeight(laUiItem *ui);
+int la_SymbolGetHeight(laUiItem *ui);
+int la_GroupGetHeight(laUiItem *ui);
+
+laPanel *la_FindFreePanelByTemplate(laWindow *w, const laUiTemplate *uit);
+laUiItem *la_FindUiWithMark(laUiList *uil, char *mark);
+laUiList *la_FindSubListWithInstance(laUiItem *ui, void *Instance);
+
+#define LA_FILETYPE_UNKNOWN 0
+#define LA_FILETYPE_UDF 1
+#define LA_FILETYPE_DOCUMENT 2
+#define LA_FILETYPE_IMAGE 3
+#define LA_FILETYPE_AUDIO 4
+#define LA_FILETYPE_VIDEO 5
+#define LA_FILETYPE_COMPRESSED 6
+#define LA_FILETYPE_FONT 7
+#define LA_FILETYPE_VECTOR 8
+#define LA_FILETYPE_WEBPAGE 9
+#define LA_FILETYPE_META 10
+#define LA_FILETYPE_BLEND 11
+#define LA_FILETYPE_PDF 13
+#define LA_FILETYPE_EXEC 14
+#define LA_FILETYPE_SYS 15
+#define LA_FILETYPE_FOLDER 16
+#define LA_FILETYPE_LASDEXCHANGE 17
+
+#define LA_FILE_SELECT_FILE 0
+#define LA_FILE_SELECT_FOLDER 1
+
+STRUCTURE(laFileItem){
+    laListItem Hyper;
+    int IsFolder;
+    char Name[1024];
+    int Size;
+    laTimeInfo TimeModified;
+    int Type;
+};
+
+STRUCTURE(laDiskItem){
+    laListItem Hyper;
+    char ID;
+    real Total_GB;
+    real Free_GB;
+};
+
+STRUCTURE(laFileBrowser){
+    laListItem Hyper;
+    char Path[1024];
+    char FileName[512];
+    laDiskItem *RootDisk;
+    laFileItem *Active;
+    laListHandle FileList;
+    laListHandle Disks;
+
+    int SelectFolder;
+};
+
+STRUCTURE(laUDFPreviewExtra){
+    laUDF *UDF;
+    laListHandle ContentNodes;
+    int Opened;
+};
+
+STRUCTURE(laManagedSaveExtra){
+    int ShowPage;
+    int OnExit;
+};
+
+#define LA_UDF_SHARE_POINTER(id) \
+    la_UDFAppendSharedTypePointer("" #id, id)
+
+laCanvasTemplate *la_GetCanvasTemplate(char *TargetContainerID, char* TemplateID);
+laPropContainer* laUiHasExtraProps(laUiType *ut, int size, int hyper);
+laPropContainer* laCanvasHasExtraProps(laCanvasTemplate *ct, int size, int hyper);
+laUiType *la_RegisterUiType(const char *Identifer, int ForType, const char *UseOperator, laBoxedTheme **bt, laUiDrawFunc *Draw, laUiGetHeightFunc GetHeight, laUiInitFunc Init, laUiDestroyFunc Destroy);
+
+void laSetWindowCursor(int id);
+void laRenameWindow(laWindow* wnd, char* name);
+
+int laGetReady();
+laWindow *laDesignWindow(int X, int Y, int W, int H);
+laLayout *laDesignLayout(laWindow *w, char *Title);
+void laFoldBlockTitle(laBlock* b);
+void laUnfoldBlockTitle(laBlock* b);
+void laMaximizeBlock(laBlock* b);
+void laRestoreToLayout();
+void laMaximizeCanvasUI(laUiItem* ui, laPanel* UiParentPanel);
+void laRestoreCanvasUI();
+void laHideMenuBar();
+void laShowMenuBar();
+void laSplitBlockHorizon(laBlock *b, real Percentage);
+void laSplitBlockVertical(laBlock *b, real Percentage);
+void laCombineChildBlocks(laBlock *b);
+laBlock *laBlock1(laBlock *b);
+laBlock *laBlock2(laBlock *b);
+laBlock *laSwapSubBlocks(laBlock *b);
+void laDestroyBlocksRecursive(laBlock *Root);
+laPanel* laTearOffPanel(laBlock* b, laPanel* p_if_set);
+void laDockPanel(laWindow* from, laBlock* b, laPanel* p);
+laPanel *laCreatePanel(laBlock *b, char *template_id);
+laPanel *laCreateTopPanel(laWindow *w, char *template_id, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB);
+void laShowPanel(laPanel *p);
+void laShowPanelWithDropDownEffect(laPanel *p);
+void laShowPanelWithExpandEffect(laPanel *p);
+void laHidePanel(laPanel *p);
+void laHidePanelWithDissoveEffect(laPanel *p);
+void laActivatePanel(char* TemplateID, int x, int y);
+void laPanPanel(laPanel *p, int DeltaX, int DeltaY);
+int laPanUiListFree(laUiList *uil, int X, int Y);
+int laPanUiList(laUiList *uil, int X, int Y, int L, int R, int U, int B);
+int laPanUiListAuto(laUiList *uil, int X, int Y, int L, int R, int U, int B);
+int laScaleUiList(laUiList *uil, real factor, int L, int R, int U, int B);
+laPanel *laDesignPropPanel(char *Title, int X, int Y, int W, int H,
+                           laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps);
+laPanel *laDesignOperatorPanel(char *Title, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB,
+                               laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps);
+void laDeferedDestroyPanel(laPanel *p);
+void laDestroySinglePanel(laPanel *p);
+void laEnsurePanelInBound(laPanel *p,laUiList* uil);
+int laEnclosePanelContent(laPanel *p, laUiList *uil);
+laPanel *laEnableIdlePanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laPropPack *This,
+                               int L, int R, int B, int MaxGH, int MaxW, laEvent *e);
+laPanel *laEnablePropertyPanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laPropPack *This,
+                               int L, int R, int B, int MaxGH, int MaxW, laEvent *e);
+laPanel *laEnableEmptyPropertyPanel(laPanel *Attachment, laOperator *a, int L, int R, int U, int MaxGH, laEvent *e);
+laPanel *laEnableMenuPanel(laPanel *Attachment, laOperator *a, laUiList *MenuRefer, laPropPack *This,
+                           int L, int R, int B, int MaxGH, int MaxW, laEvent *e);
+laPanel *laDefineAndEnableMenuPanel(laPanel *Attachment, laOperator *a, laPropPack *This,
+                                    int L, int B, int MaxGH, int MaxW, laEvent *e);
+laPanel *laEnableOperatorPanel(laOperator *For, laPropPack *This, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB, laEvent *e);
+laPanel *laEnableYesNoPanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e);
+laPanel *laEnableMessagePanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e);
+laPanel *laEnableMultiMessagePanel(laOperator *a, laPanel *Attachment, char *Title, laPanelMessageList *pml, int X, int Y, int W, laEvent *e);
+void laAddPanelMessage(laPanelMessageList *pml, char *Message);
+
+void la_PropPanelUserRemover(void* This, laItemUserLinker* iul);
+
+void la_EnsurePanelExtras(laPanel *p);
+
+void laRedrawAllWindows();
+void laRedrawCurrentWindow();
+void laRedrawCurrentPanel();
+void laRecalcCurrentPanel();
+void laRecalcPanelImmediate(laPanel *p);
+void laRecalcCurrentPanelImmediate();
+int laNonFixedPanelExists(laPanel *p);
+int laIsInPanel(laPanel *p, int PanelX, int PanelY);
+int laIsCloseToPanel(laPanel *p, int PanelX, int PanelY);
+void laPopPanel(laPanel *p);
+int laPanelOverlappingEachOther(laPanel *p1, laPanel *p2);
+void laUnlinkSharedPanel(laPanel *p);
+int laIsPanelCovered(laPanel *p);
+int laIsTopPanel(laPanel *p);
+laPanel *laDetectPanel(int X, int Y);
+void laWindowToLocal(laOperator *a, laPanel *p, int *x, int *y);
+void laPanelToLocal(laOperator *a, int *x, int *y);
+void laLocalToWindow(laOperator *a, laPanel *p, int *x, int *y);
+void laLocalToPanel(laOperator *a, int *x, int *y);
+void laSetNextMenuPos(int X, int Y, int W, int H);
+int laIsInBlock(laBlock *b, int X, int Y);
+int laIsInBlockHeader(laBlock *b, int X, int Y);
+int laIsInBlockBotton1(laBlock *b, int X, int Y);
+int laIsInBlockBotton2(laBlock *b, int X, int Y);
+laBlock *laDetectBlockRecursive(laBlock *b, int X, int Y);
+
+laUiList *laPrepareUi(laPanel *p);
+laColumn *laFirstColumn(laUiList *uil);
+laColumn *laSplitColumn(laUiList *uil, laColumn *c, real Percent);
+laColumn *laSplitColumnDescriptor(laUiDescriptor *ud, laColumn *c, real Percent);
+laColumn *laLeftColumn(laColumn *c, int MaxWidth);
+laColumn *laRightColumn(laColumn *c, int MaxWidth);
+
+int laCheckAndMergeSubColumnsUiList(laUiList *TopUil, laColumn *c, int DoMerge);
+int laCheckAndMergeSubColumnsDescriptor(laUiDescriptor *TopDescriptor, laColumn *c, int DoMerge);
+
+laUiConditionNode *laTrue();
+laUiConditionNode *laFalse();
+laUiConditionNode *laPropExpression(laPropPack *Base, char *Prop);
+laUiConditionNode *laIntExpression(int Value);
+laUiConditionNode *laFloatExpression(real Value);
+laUiConditionNode *laStringExpression(char *Content);
+laUiConditionNode *laAnd(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+laUiConditionNode *laOr(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+laUiConditionNode *laNot(laUiConditionNode *Expression1);
+laUiConditionNode *laEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+laUiConditionNode *laGreaterThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+laUiConditionNode *laLessThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+laUiConditionNode *laGreaterEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+laUiConditionNode *laLessEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2);
+
+laUiItem *laShowLabel(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget);
+laUiItem *laShowLabelDynamic(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget);
+laUiItem *laShowIcon(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget);
+laUiItem *laShowItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path);
+laUiItem *laShowItemFull(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget, char* instructions, laUiDefineFunc Template, int TemplateContext);
+laUiItem *laShowNodeSocket(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions);
+laUiItem *laShowHeightAdjuster(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions);
+laUiItem *laShowDetachedItem(laPanel *p, laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *Rename, laUiDefineFunc Template, laWidget* Widget);
+laUiItem *laShowCanvas(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *id2DTemplate, int Height);
+laUiItem *laShow2DContainerItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height);
+void laDefault3DViewOverlay(laUiItem *ui);
+void laDefault2DViewOverlayRight(laUiItem *ui);
+laUiItem *laShowColumnAdjuster(laUiList *uil, laColumn *c);
+laUiItem *laShowSymbol(laUiList *uil, laColumn *c, int SymbolID, int Height);
+laUiItem *laBeginRow(laUiList *uil, laColumn *c, int Expand, int Even);
+laUiItem *laEndRow(laUiList *uil, laUiItem* Begin);
+laUiItem *laMakeGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget);
+laUiItem *laMakeFoldableGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget, int DefaultFolded);
+laUiItem *laMakeEmptyGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget);
+void laEndFoldableGroup(laUiList *sub, laUiItem *group);
+laUiItem *laMakeTab(laUiList *uil, laColumn *c, laWidget* Widget);
+laUiList *laAddTabPage(laUiItem *ui, const char *Name);
+laUiItem *laOnConditionThat(laUiList *uil, laColumn *c, laUiConditionNode *Expression);
+laUiItem *laOnConditionToggle(laUiList *uil, laColumn *col, laUiDefineFunc define, int Remove, laPropPack *ExtraBase, laPropPack *ExtraThis, laWidget* Widget);
+laUiItem *laEndCondition(laUiList *uil, laUiItem *Beginner);
+laUiItem *laElse(laUiList *uil, laUiItem *Beginner);
+laUiList *laMakeMenuPage(laUiList *uil, laColumn *c, const char *Title);
+laUiItem *laShowSeparator(laUiList *uil, laColumn *widest);
+void laFixHeight(laUiList *uil, short Rows);
+
+void la_ConditionerInit(laUiItem *ui, laUiConditionNode *Expression);
+
+void laMakeExtraColumns(laUiItem *ui, u8bit HowMany, ...);
+
+int la_UiInBoundEx(laUiItem *ui, laUiListDraw *uild);
+
+void la_DestroyUiRange(laUiList *uil, laUiItem *Begin, laUiItem *End);
+void la_ClearUiSpecificData(laUiItem *ui);
+laUiItem *la_UpdatePropDisplay(laUiItem *ui, laPropPack *Base, const char *Path, laUiDefineFunc Template, laWidget* Widget, char* instructions);
+laUiItem *la_UpdateLabelDisplay(laUiItem *ui, laUiDefineFunc Template, char *Content);
+laUiItem *la_ShowGeneralPropItem(laUiList *uil, laColumn *c, laPropPack *Base, laProp *GeneralProp, laProp *p, laUiDefineFunc Template, laWidget* Widget);
+
+void laFinalizeUiTemplates();
+laUiTemplate *laFindUiTemplate(char *Identifier);
+
+void la_DestroyUiTemplate(laUiTemplate* uit);
+void la_DestroyCanvasTemplate(laCanvasTemplate* uit);
+laUiTemplate *laRegisterUiTemplate(char *Identifier, char* Title, laUiDefineFunc func,laPanelDetachedPropFunc PropFunc, laUiDefineFunc header);
+laCanvasTemplate *laRegisterCanvasTemplate(char *Identifier, char *ForContainer, laCanvasDrawFunc Func, laUiDrawFunc SecondDraw, laUiInitFunc CustomInit, laUiDestroyFunc CustomDestroy);
+
+void laGet2DViewRange(laCanvasExtra *e, int *L, int *R, int *U, int *B);
+void laGet2DViewRanged(laCanvasExtra *e, real *L, real *R, real *U, real *B);
+void laGet2DViewRangeW(laCanvasExtra *e, int *L, int *R);
+void laGet2DViewRangeWd(laCanvasExtra *e, real *L, real *R);
+
+void la_DestroyTheme(laTheme* t);
+laTheme *laDesignTheme(const char *Name, const char *AuthorName);
+laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** BackRef,
+                                 real NormalY,real ActiveY,real BorderY,real TextY,real TextActiveY, real Alpha,
+                                 real TopMargin,  real LeftMargin,  real RightMargin,  real BottomMargin,
+                                 real TopPadding, real LeftPadding, real RightPadding, real BottomPadding);
+laBoxedTheme *laGetTheme(const char *ThemeName);
+laBoxedTheme *laGetBoxedTheme(const char *ThemeName, const char *BoxName);
+real* laThemeColor(laBoxedTheme* bt, int which);
+real* laAccentColor(int which);
+
+void la_RefreshBoxedThemeColor(laBoxedTheme* bt);
+void la_RefreshThemeColorSelf(laTheme* th);
+void la_RefreshThemeColor(laTheme* th);
+
+#define LA_COLOR4(c) (c)[0], (c)[1], (c)[2], (c)[3]
+#define LA_COLOR3(c) (c)[0], (c)[1], (c)[2]
+#define LA_VEC2(c) (c)[0], (c)[1]
+#define LA_SET3(c, a1,a2,a3) { (c)[0]=a1; (c)[1]=a2; (c)[2]=a3; }
+
+int laIsInUiItem(laUiItem *ui, int x, int y);
+int laIsInBound(int x, int y, int l, int r, int u, int b);
+laUiItem *la_DetectUiItemRecursive(laUiList *uil, int x, int y, int LimB, laListHandle *LocalBuf, int Deep);
+laUiItem *la_DetectSocketRecursive(laUiList* uil, int x, int y, int LimB, laPropContainer* PCInOrOut);
+laUiList *la_DetectUiListRecursive(laUiList *uil, int x, int y, int LimH,
+                                   laUiItem **ParentUi, laUiList **ScrollUil, laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception);
+laUiList *la_DetectUiListRecursiveDeep(laUiList *uil, int x, int y, int LimH, laUiItem **ParentUi, laUiList **ScrollUil,
+                                       laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception, laListHandle* levels);
+
+int laStartWindow(laWindow *w);
+
+void laMainLoop();
+
+void la_DestroyOperatorType(laOperatorType* at);
+laOperatorType *laCreateOperatorType(const char *ID, const char *Name, const char *Description,
+                                     laCheckFunc Check, laInitFunc Init, laExitFunc Exit, laInvokeFunc Invoke, laModalFunc Modal,
+                                     uint32_t IconID, int ExtraMark);
+
+laPropContainer* laDefineOperatorProps(laOperatorType* ot, int HyperLevel);
+
+
+laNodeOutSocket* laCreateOutSocket(void* NodeParentOptional, char* label, int DataType);
+laNodeInSocket* laCreateInSocket(char* label, int DataType);
+
+
+void laFreeKeyMapItem(laKeyMapItem* kmi);
+laKeyMapItem *laAssignNewKey(laKeyMapper *km, char *Path, char *Operation, char SelectBase, int SpecialKeyBits, int EventType, int Key, char *ExtraInstructions);
+int laKeyMapExecuteEvent(laOperator *from, laKeyMapper *km, laEvent *e);
+int laKeyMapExecuteEventEx(laOperator *from, laPropPack *UiExtra, laKeyMapper *km, laEvent *e);
+
+laOperatorType *laGetOperatorType(const char *ID);
+void laSetOperatorLocalizer(void *ToPanel);
+
+int laOperatorAvailable(char *ID, laPropPack *This, laStringSplitor *Instructions);
+int laOperatorAvailableP(laOperatorType *at, laPropPack *This, laStringSplitor *Instructions);
+int laOperatorAvailableSafe(char *ID, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions);
+int laOperatorAvailablePSafe(laOperatorType *at, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions);
+
+void laSendOperatorTriggerEvent();
+void laRetriggerOperators();
+
+int la_GenericTopPanelProcessing(laOperator* a, laEvent* e);
+
+
+int OPMOD_FinishOnData(laOperator* a, laEvent* e);
+
+int la_UiOperatorExists(void *inst);
+int laOperatorExistsT(laOperatorType* at);
+int laOperatorExists(const char* ID);
+int laInvokeUi(laOperator *From, char *ID, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals);
+int laInvokeUiP(laOperator *From, laOperatorType *at, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals);
+int laInvoke(laOperator *From, char *ID, laEvent *e, laPropPack *This, char *args, char *args2);
+int laInvokeCreateThis(laOperator *From, char *ID, laEvent *e, laPropPack *OrigionalThis, void *FromInstance, char *args, char *args2);
+int laInvokeP(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *This, char *args, char *args2);
+int laInvokePCreateThis(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *OrigionalThis, void *FromInstance, char *args, char *args2);
+void laRequestDelayEvent(real Seconds);
+
+int la_UiStillInService(void *UiInstance);
+void la_StopUiOperatorService(void *UiInstance);
+void la_StopAllOperators();
+
+int la_ProcessTextEdit(laEvent *e, laStringEdit *se, laUiItem* ui);
+
+void laConfirmInt(laOperator *a, int Data, int mode);
+void laConfirmFloat(laOperator *a, real Data, int mode);
+void laConfirmString(laOperator *a, char *Str, int mode);
+int laConfirmSameDataIfAny(laOperator *a);
+void laConfirmUserData(laOperator *a, void *UserData, laConfirmDataDestroyFunc Destroy, int mode);
+int laGetConfirmInt(laOperator *a);
+real laGetConfirmFloat(laOperator *a);
+void laGetConfirmString(laOperator *a, char *buf);
+void *laGetConfirmUserData(laOperator *a);
+//int laInvokeSub(laProp* From, char * ID, laEvent* e, void* inst);
+
+void laFinalizeOperators();
+
+int laWaitFor(laOperator *Who, int State);
+
+void la_PrintOperatorStack();
+
+void laui_DefaultPanelTitleBar(laUiList *uil, laPropPack *Base, laPropPack *Extra, laUiDefineFunc header);
+void laui_DefaultOperatorPanelTitleBar(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context);;
+void laui_DefaultSubWindowMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context);;
+void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context);;
+void laui_DefaultMenuBar(laWindow *w);
+void laui_DefaultSubWindowMenuBar(laWindow *w);
+void laui_DefaultPropUiDefine(laUiList *uil, laPropPack *This, laPropPack *OperatorProps, laColumn *UNUSED, int context);;
+
+int laCopyToClipboard(unsigned char * text);
+
+void laRegisterInternalNodes() ;
+
+extern laUiType *_LA_UI_FIXED_GROUP;
+extern laUiType *_LA_UI_TAB;
+extern laUiType _LA_UI_CONDITION;      //NO PTR
+extern laUiType _LA_UI_CONDITION_END;  //NO PTR
+extern laUiType _LA_UI_CONDITION_ELSE; //NO PTR
+extern laUiType _LA_UI_ROW_BEGIN;      //NO PTR
+extern laUiType _LA_UI_ROW_END;        //NO PTR
+extern laUiType *_LA_UI_COLLECTION;
+extern laUiType *_LA_UI_COLLECTION_ITEM;
+extern laUiType *_LA_UI_COLLECTION_SELECTOR;
+extern laUiType *_LA_UI_COLLECTION_SINGLE;
+extern laUiType *_LA_UI_BUTTON;
+extern laUiType *_LA_UI_LABEL;
+extern laUiType *_LA_UI_INT;
+extern laUiType *_LA_UI_INT_METER;
+extern laUiType *_LA_UI_INT_METER_2D;
+extern laUiType *_LA_UI_FLOAT;
+extern laUiType *_LA_UI_FLOAT_COLOR;
+extern laUiType *_LA_UI_FLOAT_HCY;
+extern laUiType *_LA_UI_ENUM_SELECTOR;
+extern laUiType *_LA_UI_MENU_ROOT;
+extern laUiType *_LA_UI_CONDITION_TOGGLE;
+extern laUiType *_LA_UI_STRING;
+extern laUiType *_LA_UI_STRING_MULTI;
+extern laUiType *_LA_UI_ALIGN;
+extern laUiType *_LA_UI_CANVAS;
+extern laUiType *_LA_UI_COLUMN_ADJUSTER;
+extern laUiType *_LA_UI_SYMBOL;
+extern laUiType *_LA_UI_COLUMN_VIEWER;
+extern laUiType *_LA_UI_NODE_SOCKET;
+extern laUiType *_LA_UI_HEIGHT_ADJUSTER;
+extern laUiType *_LA_UI_RAW;
+ 
+extern laUiDescriptor _LA_UI_DESCRIPTOR_REF_UI;
+extern laUiDescriptor _LA_UI_DESCRIPTOR_REF_UIE;
+extern laUiDescriptor _LA_UI_DESCRIPTOR_REF_P;
+extern laUiDescriptor _LA_UI_DESCRIPTOR_REF_PE;
+extern laUiDescriptor _LA_UI_DESCRIPTOR_REF_BASE;
+extern laUiDescriptor _LA_UI_DESCRIPTOR_REF_ACT;
+
+extern laUiDefineFunc _LA_SUBPROP_DONT_CARE;
+ 
+extern laBoxedTheme *_LA_THEME_PANEL;
+extern laBoxedTheme *_LA_THEME_VALUATOR;
+extern laBoxedTheme *_LA_THEME_BUTTON;
+extern laBoxedTheme *_LA_THEME_STRING;
+extern laBoxedTheme *_LA_THEME_SELECTOR;
+extern laBoxedTheme *_LA_THEME_COLLECTION_SELECTOR;
+extern laBoxedTheme *_LA_THEME_LABEL;
+extern laBoxedTheme *_LA_THEME_TAB;
+extern laBoxedTheme *_LA_THEME_COLLECTION_GROUP;
+extern laBoxedTheme *_LA_THEME_COLLECTION_ITEM;
+extern laBoxedTheme *_LA_THEME_FLOATING_PANEL;
+extern laBoxedTheme *_LA_THEME_3D_VIEW;
+extern laBoxedTheme *_LA_THEME_2D_VIEW;
+extern laBoxedTheme *_LA_THEME_SOCKET;
+
+extern laProp *_LA_PROP_PANEL;
+extern laProp *_LA_PROP_BLOCK;
+extern laProp *_LA_PROP_WINDOW;
+extern laProp *_LA_PROP_UI_ITEM;
+extern laProp *_LA_PROP_FAILED_ITEM;
+extern laProp *_LA_PROP_TRASH_ITEM;
+extern laProp *_LA_PROP_NODE_GRAPH;
+extern laPropContainer *_LA_PROP_3D_EXTRA;
+extern laPropContainer *_LA_PROP_2D_EXTRA;
+extern laPropContainer *_LA_PROP_FILE_BROWSER;
+ 
+extern laProp _P_LA_USE_INSTANCE_ONLY;
+#define _LA_USE_INSTANCE_ONLY (&_P_LA_USE_INSTANCE_ONLY)
+
+#define LA_CARE_ALL64 (~(0ull))
+#define LA_CARE_ALL32 (~(0ull))
+
+#define LA_MATCH_INSTANCE (1ull << 63)
+
+#define LA_IN_USER_PREF (1ull << 62)
+#define LA_IN_LIVE_EDIT (1ull << 61)
+#define LA_IN_PANEL (1ull << 60)
+#define LA_IN_WINDOW (1ull << 59)
+#define LA_IN_LAYOUT (1ull << 58)
+
+#define LA_USER_THEME (1ull << 63)
+#define LA_USER_THEME_SIZE (1ull << 62)
+#define LA_USER_THEME_COLOR (1ull << 61)
+#define LA_USER_DISPLAY (1ull << 60)
+
+#define LA_LIVE_PATH (1ull << 63)
+#define LA_LIVE_TYPE (1ull << 62)
+#define LA_LIVE_THEME (1ull << 61)
+#define LA_LIVE_EXTRA (1ull << 60)
+
+#define LA_WINDOW_INFO (1ull << 63)
+
+#define LA_LAYOUT_INFO (1ull << 63)
+
+#define LA_UI_INTERNAL_BUTTON 1
+#define LA_UI_INTERNAL_WATCHER 2
+#define LA_UI_INTERNAL_GROUP 3
+#define LA_UI_INTERNAL_TAB 4
+#define LA_UI_INTERNAL_LABEL 5
+#define LA_UI_INTERNAL_3D_VIEW 6
+#define LA_UI_INTERNAL_2D_VIEW 7
+#define LA_UI_INTERNAL_ADJUSTER 8
+#define LA_UI_INTERNAL_BRACKET_BEGIN 9
+#define LA_UI_INTERNAL_BRACKET_ELSE 10
+#define LA_UI_INTERNAL_FOLDER_BEGIN 11
+#define LA_UI_INTERNAL_BRACKET_END 12
+#define LA_UI_INTERNAL_ALIGNER 13
+#define LA_UI_INTERNAL_MENU 14
+#define LA_UI_INTERNAL_SYMBOL 15
+
+#define LA_RH0 (MAIN.UiRowHeight)
+#define LA_RH (MAIN.ScaledUiRowHeight)
+#define LA_2RH (MAIN.ScaledUiRowHeight*2)
+#define LA_RH2 ((int)(MAIN.ScaledUiRowHeight/2))
+#define LA_SCROLL_W ((int)(MAIN.ScaledUiRowHeight * 0.67))
+#define LA_SEAM_W ((int)(MAIN.ScaledUiRowHeight * 0.15))

+ 6402 - 0
source/lagui/la_kernel.c

@@ -0,0 +1,6402 @@
+#include "la_5.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <time.h>
+#include <sys/time.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xos.h>
+#include <X11/keysymdef.h>
+#include <X11/XKBlib.h>
+#include <GL/glx.h>
+//#include <GL/glext.h>
+//#include <GL/glu.h>
+
+LA MAIN;
+
+extern tnsMain *T;
+int deb = 0;
+
+laOperator *DEB;
+
+laColumn *DEBUG_C;
+
+Atom XA_ATOM = 4, XA_STRING = 31;
+
+#define LA_GUI_WNDCLASS_NAME "NUL4_GUI_CLASS"
+
+typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);
+typedef Bool (*glXMakeContextCurrentARBProc)(Display*, GLXDrawable, GLXDrawable, GLXContext);
+typedef void (*glXSwapIntervalEXTProc)(Display *dpy, GLXDrawable drawable, int interval);
+
+glXCreateContextAttribsARBProc glXCreateContextAttribsF;
+glXSwapIntervalEXTProc glXSwapIntervalEXTF;
+
+Window la_CreateWindowX11(int x, int y, int w, int h, char *title, int SyncToVBlank, GLXContext* r_glc){
+    XSetWindowAttributes swa;
+    XWindowAttributes wa;
+    swa.event_mask = 
+        KeyPressMask|KeyReleaseMask|StructureNotifyMask|SubstructureNotifyMask|
+        ButtonMotionMask|ButtonPressMask|ButtonReleaseMask|ExposureMask|PointerMotionMask;
+    swa.colormap = MAIN.cmap;
+    Window root = DefaultRootWindow(MAIN.dpy);
+    Window win = XCreateWindow(MAIN.dpy, root, x, y, w, h, 0, MAIN.xvi->depth, InputOutput, MAIN.xvi->visual, CWColormap | CWEventMask, &swa);
+    XSetWMProtocols(MAIN.dpy , win, &MAIN.MsgDelWindow, 1);
+
+    if(x>0||y>0){
+        XSizeHints    my_hints = {0};
+        my_hints.flags = PPosition;
+        my_hints.x = x; my_hints.y = y;
+        XSetNormalHints(MAIN.dpy, win, &my_hints);
+    }
+
+    //int attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, 0};
+    //if (((*r_glc) = glXCreateContextAttribsF(MAIN.dpy, MAIN.BestFBC, MAIN.glc, GL_TRUE, attribs)) == NULL){
+    //    printf("\n\tcannot create gl context\n\n"); exit(0);
+    //}
+
+    XStoreName(MAIN.dpy, win, title);
+    XMapWindow(MAIN.dpy, win);
+    glXMakeContextCurrent(MAIN.dpy, win, win, MAIN.glc);
+
+    int sync=SyncToVBlank?1:0; glXSwapIntervalEXTF(MAIN.dpy, win, sync);
+
+    MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL);
+    MAIN.ic = XCreateIC(MAIN.im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL);
+    XSetICFocus(MAIN.ic);
+
+    XClassHint ch; ch.res_name = "LAGUI_WINDOW"; ch.res_class = "LAGUI_WINDOW";
+    XSetClassHint(MAIN.dpy, win, &ch);
+
+
+#define _NET_WM_STATE_ADD 1
+    if(w<0&&h<0){
+        XEvent xev;
+        Atom wm_state  =  XInternAtom(MAIN.dpy, "_NET_WM_STATE", False);
+        Atom max_horz  =  XInternAtom(MAIN.dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
+        Atom max_vert  =  XInternAtom(MAIN.dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
+        memset(&xev, 0, sizeof(xev));
+        xev.type = ClientMessage;
+        xev.xclient.window = win;
+        xev.xclient.message_type = wm_state;
+        xev.xclient.format = 32;
+        xev.xclient.data.l[0] = _NET_WM_STATE_ADD;
+        xev.xclient.data.l[1] = max_horz;
+        xev.xclient.data.l[2] = max_vert;
+        XSendEvent(MAIN.dpy, DefaultRootWindow(MAIN.dpy), False, SubstructureNotifyMask, &xev);
+    }
+
+    return win;
+};
+int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){
+    GLXContext glc;
+    Window hwnd = la_CreateWindowX11(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc);
+    window->win = hwnd;
+    //if (!hwnd)
+    //{
+    //    MessageBox(0, "Error Creating Window!", "Error", 0);
+    //    return 0;
+    //};
+    //ImmAssociateContext(hwnd,0);
+
+    //la_SetupGLEnviornment(window, hwnd);
+
+    //GetClientRect(window->win, &rc);
+    //window->CW = rc.right - rc.left;
+    //window->CH = rc.bottom - rc.top;
+
+    XWindowAttributes attr;
+    XGetWindowAttributes(MAIN.dpy, window->win, &attr);
+    window->CW =attr.width;
+    window->CH = attr.height;
+    window->glc = glc;
+    return 1;
+};
+void la_DestroySystemWindowX11(laWindow* w){
+    glXMakeCurrent(MAIN.dpy, None, NULL);
+    //glXDestroyContext(MAIN.dpy, w->glc);
+    XDestroyWindow(MAIN.dpy, w->win);
+};
+int la_DestroySystemWindow(laWindow* wnd){
+    la_DestroySystemWindowX11(wnd);
+}
+
+void la_DestroyWindow(laWindow *wnd){
+    laLayout *l; laPanel *p;
+
+    if (!wnd) return;
+
+    strSafeDestroy(&wnd->Title);
+
+    while (p = lstPopItem(&wnd->Panels)){
+        laDestroySinglePanel(p);
+    }
+    while (l = lstPopItem(&wnd->Layouts)){
+        laDestroyBlocksRecursive(l->FirstBlock);
+        strSafeDestroy(&l->ID);
+        memFree(l);
+    }
+    la_DestroySystemWindow(wnd);
+    lstRemoveItem(&MAIN.Windows, wnd);
+
+    memFree(wnd);
+}
+
+void laRenameWindow(laWindow* wnd, char* name){
+    strSafeSet(&wnd->Title, name);
+    XStoreName(MAIN.dpy, wnd->win, name);
+}
+
+int la_ConvertCursorID(int id){
+    return 0;
+    //switch (id)
+    //{
+    //case LA_ARROW:
+    //    return IDC_ARROW;
+    //case LA_CROSS:
+    //    return IDC_CROSS;
+    //case LA_LEFT_RIGHT:
+    //    return IDC_SIZEWE;
+    //case LA_UP_AND_DOWN:
+    //    return IDC_SIZENS;
+    //case LA_MOVE:
+    //    return IDC_SIZEALL;
+    //case LA_HAND:
+    //    return IDC_HAND;
+    //}
+}
+
+void la_MakePanelTitleBar(laPanel *p, laUiDefineFunc ReplaceDefine);
+void la_InitThreadEnviornment(){
+    //pthread_spin_init(&MAIN.csNotifier, //pthread_PROCESS_PRIVATE);
+}
+
+laLogEntry* logEnsure(int Create){
+    if(!MAIN.Logs.pFirst || Create){
+        laLogEntry* le=memAcquireSimple(sizeof(laLogEntry));
+        lstAppendItem(&MAIN.Logs, le);
+    }
+    return MAIN.Logs.pLast;
+}
+void logPrintTV(int Continued, char* format, va_list v){
+    if(!format || !format[0]) return;
+    laLogEntry* le=logEnsure(Continued);
+    va_list aptr;
+    strSafePrintV(&le->Content, format, v);
+    laNotifyUsers("la.logs");
+}
+void logPrintT(int Continued, char* format, ...){
+    if(!format || !format[0]) return;
+    laLogEntry* le=logEnsure(Continued);
+    va_list aptr; va_start(aptr, format);
+    strSafePrint(&le->Content, format, aptr);
+    va_end(aptr);
+    laNotifyUsers("la.logs");
+}
+void logPrint(char* format, ...){
+    va_list aptr; va_start(aptr, format);
+    logPrintTV(0, format, aptr);
+    va_end(aptr);
+}
+void logPrintNew(char* format, ...){
+    logEnsure(1);
+    va_list aptr; va_start(aptr, format);
+    logPrintTV(0, format, aptr);
+    va_end(aptr);
+}
+void logClear(){
+    laLogEntry*l;
+    while(l=lstPopItem(&MAIN.Logs)){ strSafeDestroy(&l->Content); memFree(l); }
+}
+
+//=======================
+
+int laGetReady(){
+    Window root, win;
+    GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
+    XSetWindowAttributes swa={0};
+    XWindowAttributes wa={0};
+    XEvent xev;
+
+    logPrintNew("Initializing LaGUI...\n");
+
+    setlocale(LC_CTYPE, "zh_CN.utf8");
+    XSetLocaleModifiers("");
+
+    int i;
+
+    if ((MAIN.dpy = XOpenDisplay(NULL)) == NULL){
+        printf("\n\tcannot connect to x server\n\n");
+        exit(0);
+    }
+
+    static int visual_attribs[] =
+    {
+      GLX_X_RENDERABLE    , True,
+      GLX_DRAWABLE_TYPE   , GLX_WINDOW_BIT,
+      GLX_RENDER_TYPE     , GLX_RGBA_BIT,
+      GLX_X_VISUAL_TYPE   , GLX_TRUE_COLOR,
+      GLX_RED_SIZE        , 8,
+      GLX_GREEN_SIZE      , 8,
+      GLX_BLUE_SIZE       , 8,
+      GLX_ALPHA_SIZE      , 8,
+      GLX_DEPTH_SIZE      , 24,
+      //GLX_STENCIL_SIZE    , 8,
+      GLX_DOUBLEBUFFER    , True,
+      GLX_SAMPLE_BUFFERS  , 1,
+      GLX_SAMPLES         , 4,
+      None
+    };
+
+    int fbcount = -1;
+    GLXFBConfig* fbconfig = glXChooseFBConfig(MAIN.dpy, DefaultScreen(MAIN.dpy), visual_attribs, &fbcount );
+
+    logPrint("glXChooseFBConfig matched %d\n",fbcount);
+
+    if (!fbcount){ printf("\n\tno matching visual\n\n"); exit(0); }
+
+    MAIN.BestFBC = fbconfig[0];
+    int sample_buf,samples;
+    glXGetFBConfigAttrib(MAIN.dpy, MAIN.BestFBC, GLX_SAMPLE_BUFFERS, &sample_buf);
+    glXGetFBConfigAttrib(MAIN.dpy, MAIN.BestFBC, GLX_SAMPLES, &samples);
+    logPrint("    Chosen framebuffer with: %s %d samples\n",sample_buf?"Multisample":"-",samples);
+
+    MAIN.xvi=glXGetVisualFromFBConfig(MAIN.dpy, MAIN.BestFBC);
+
+    root = DefaultRootWindow(MAIN.dpy);
+    if ((MAIN.cmap = XCreateColormap(MAIN.dpy, root, MAIN.xvi->visual, AllocNone)) == 0){
+        printf("\n\tcannot create colormap\n\n"); exit(0);
+    }
+
+    swa.colormap = MAIN.cmap;
+    root = DefaultRootWindow(MAIN.dpy);
+    win = XCreateWindow(MAIN.dpy, root, 0, 0, 100, 100, 0, MAIN.xvi->depth, InputOutput, MAIN.xvi->visual, CWColormap | CWEventMask, &swa);
+
+    int attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 4, GLX_CONTEXT_MINOR_VERSION_ARB, 6, 0};
+    glXCreateContextAttribsF = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" );
+    if ((MAIN.glc = glXCreateContextAttribsF(MAIN.dpy, MAIN.BestFBC, NULL, GL_TRUE, attribs)) == NULL){
+        printf("\n\tcannot create gl context\n\n"); exit(0);
+    }
+    glXSwapIntervalEXTF = (glXSwapIntervalEXTProc) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalEXT" );
+
+    glXMakeContextCurrent(MAIN.dpy, win,win, MAIN.glc);
+
+    int major,minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor);
+    logPrint("    OpenGL Version: %d.%d\n",major,minor);
+    logPrint("    OpenGL Renderer: %s\n",glGetString(GL_RENDERER));
+
+    int err=0;
+    if((err=glewInit())!=GLEW_OK){
+        printf("%d\n",err); printf("%s\n",glewGetErrorString(err));
+    };
+
+    MAIN.MsgDelWindow = XInternAtom(MAIN.dpy, "WM_DELETE_WINDOW", 0);
+    MAIN.bufid =  XInternAtom(MAIN.dpy, "CLIPBOARD", False),
+    MAIN.fmtid =  XInternAtom(MAIN.dpy, "UTF8_STRING", False),
+    MAIN.propid = XInternAtom(MAIN.dpy, "XSEL_DATA", False),
+    MAIN.incrid = XInternAtom(MAIN.dpy, "INCR", False);
+    MAIN.targets_atom = XInternAtom(MAIN.dpy, "TARGETS",0);
+    MAIN.text_atom =    XInternAtom(MAIN.dpy, "TEXT", 0);
+    MAIN.UTF8 =         XInternAtom(MAIN.dpy, "UTF8_STRING", 1);
+    MAIN.selection =    XInternAtom(MAIN.dpy, "CLIPBOARD", 0);
+	if(MAIN.UTF8 == None) MAIN.UTF8 = XA_STRING;
+
+    la_GetWorkingDirectoryInternal();
+    //laSetAuthorInfo("YimingWu", "(C)Nick'sBest");
+
+    //transInitTranslation_zh_cn();
+    //transState(0, 1); //enable translation
+    MAIN.FontSize = 0.6;
+    MAIN.UiRowHeight = MAIN.ScaledUiRowHeight =24;
+    MAIN.UiScale=1;
+    MAIN.MarginSize = 1;
+
+    tnsInitRenderKernel(64);
+    tnsInitBuiltinShaders();
+
+    tnsSetuptnsFontManager();
+    tnsLoadSystemFont(4,
+        "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
+        "/home/yiming/.local/share/fonts/NotoEmoji-Regular.ttf",
+        "/home/yiming/.local/share/fonts/NotoSansSymbols-Regular.ttf",
+        "/home/yiming/.local/share/fonts/NotoSansSymbols2-Regular.ttf"
+        //"/home/yiming/.local/share/fonts/NotoMusic-Regular.ttf",
+        //"/home/yiming/.local/share/fonts/NotoSansEgyptianHieroglyphs-Regular.ttf"
+        );
+    tnsLoadSystemFontMono("/home/yiming/.local/share/fonts/NotoSansMono-Regular.ttf");
+
+    arrEnsureLength(&MAIN.InputBuf,0,&MAIN.InputBufMax,sizeof(char));
+    arrEnsureLength(&MAIN.InputBufU,0,&MAIN.InputBufUMax,sizeof(uint32_t));
+
+    //XDestroyWindow(MAIN.dpy, win);
+
+    MAIN.ColorAccessCorrectGamma = 1;
+    MAIN.Gamma = 1;//2.2; ...?
+
+    //interactions:
+    MAIN.TopFramerate = 60;
+    MAIN.ValuatorThreshold = 8;
+    MAIN.ScrollingSpeed = 3;
+    MAIN.AnimationSpeed = 0.4;
+    MAIN.PanelAnimationSpeed = 0.4;
+    MAIN.ZoomSpeed2D = 0.01;
+    MAIN.IdleTime = 0.75;
+    MAIN.TooltipCloseDistance = 30;
+
+    //display:
+    MAIN.FloatingAlpha = 0.7;
+    MAIN.SolidShadowLength = 20;
+    MAIN.TrackShadowLength = 30;
+    MAIN.WireColorSlices = 16;
+    MAIN.WireThickness = 5;
+    MAIN.WireSaggyness = 5;
+
+    //timeline:
+    MAIN.Animation.FrameBegin = 1;
+    MAIN.Animation.FrameEnd = 250;
+    MAIN.Animation.Frame = 1;
+    MAIN.Animation.FrameRate = 25;
+    MAIN.Animation.FrameStep = 1;
+
+    laAddResourceFolder(".");
+    laAddResourceFolder("/home/yiming/Documents/sync/Projects/2022/nul5/build");
+
+
+    //tns_RegisterResourcesForSoftwareRender();
+    la_RegisterGeneralProps();
+    la_RegisterInternalTemplates();
+    la_RegisterMainThemes();
+    la_RegisterMainOperators();
+    la_RegisterMainUiTypes();
+    la_RegisterModellingOperators();
+    la_RegisterInternalProps();
+    //laRegisterInternalNodes();
+    la_RegisterWindowKeys();
+
+    laFinalizeUiTemplates();
+    laFinalizeOperators();
+
+    la_InitControllers();
+    la_RegisterControllerProps();
+
+    la_InitThreadEnviornment();
+
+    laSetRootInstance(&MAIN);
+
+    laPushDifferences(0, 0);
+    la_MakeDummyManagedUDF();
+
+    la_RegenerateWireColors();
+
+    logPrint("Initialization Completed\n");
+}
+
+void laShutoff(){
+    strSafeDestroy(&MAIN.WorkingDirectory);
+    strSafeDestroy(&MAIN.example_string);
+
+    la_NoLongerRecordUndo();
+
+    laWindow* wi; while(wi=lstPopItem(&MAIN.Windows)){ la_DestroyWindow(wi); }
+    laUiTemplate* uit; while(uit=lstPopItem(&MAIN.PanelTemplates)){ la_DestroyUiTemplate(uit); }
+    laCanvasTemplate* u2t; while(u2t=lstPopItem(&MAIN.View2DTemplates)){ la_DestroyCanvasTemplate(u2t); }
+    laUiType* uit1; while(uit1=lstPopItem(&MAIN.UiTypes)){ la_DestroyUiType(uit1); }
+    laOperatorType* at; for(int i=0;i<256;i++){ while(at=lstPopItem(&MAIN.OperatorTypeHash.Entries[i])) la_DestroyOperatorType(at); }
+    laSharedTypeItem* sti; while(sti=lstPopItem(&MAIN.SharedTypePointerSync)){ memFree(sti); }
+    laKeyMapItem* kmi; while(kmi=lstPopItem(&MAIN.KeyMap.Items)){ la_FreeKeyMapItem(kmi); }
+    laTheme* t; while(t=lstPopItem(&MAIN.Themes)){ la_DestroyTheme(t); }
+
+    arrFree(&MAIN.InputBuf,&MAIN.InputBufNext);
+    arrFree(&MAIN.InputBufU,&MAIN.InputBufUNext);
+
+    strSafeDestroy(&MAIN.CopyPending);
+
+    la_ClearUDFRegistryAndFolders();
+    laClearManagedUDF();
+    laClearSaveProp();
+
+    logClear();
+
+    tnsQuit();
+
+    laPropContainer* pc; while(pc=lstPopItem(&MAIN.PropContainers)){ la_FreePropertyContainer(pc); }
+
+    strSafeDump();
+
+    memNoLonger();
+}
+
+//MSG====================================================
+
+int la_IsThisSysWindow(laWindow *wnd, Window hwnd){
+    if (wnd->win == hwnd) return 1;
+    else
+        return 0;
+};
+void la_EnsurePanelSnapping(laPanel *p, int CW, int CH){
+    if (p->SL){ int s=p->SL<0?0:p->SL;
+        if (p->TX != s) p->Refresh |= LA_TAG_RECALC;
+        p->TX = s;
+    }
+    if (p->SR){ int s=p->SR<0?0:p->SR;
+        if (p->TW != CW - p->TX - s) p->Refresh |= LA_TAG_RECALC;
+        p->TW = CW - p->TX - s;
+    }
+    if (p->ST){ int s=p->ST<0?0:p->ST;
+        if (p->TY != s) p->Refresh |= LA_TAG_RECALC;
+        p->TY = s;
+    }
+    if (p->SB){ int s=p->SB<0?0:p->SB;
+        if (p->TH != CH - p->TY - s) p->Refresh |= LA_TAG_RECALC;
+        p->TH = CH - p->TY - s;
+    }
+}
+void la_RecalcBlockRecursive(laBlock *b, int X, int Y, int W, int H){
+    laPanel *p = 0;
+    b->X = X;
+    b->Y = Y;
+    b->W = W;
+    b->H = H;
+
+    if (b->B1){
+        int SplitWidth;
+        if (b->Vertical){
+            SplitWidth = H * b->SplitRatio;
+            la_RecalcBlockRecursive(b->B1, X, Y, W, SplitWidth);
+            la_RecalcBlockRecursive(b->B2, X, Y + SplitWidth, W, H - SplitWidth);
+        }else{
+            SplitWidth = W * b->SplitRatio;
+            la_RecalcBlockRecursive(b->B1, X, Y, SplitWidth, H);
+            la_RecalcBlockRecursive(b->B2, X + SplitWidth, Y, W - SplitWidth, H);
+        }
+    }
+
+    //if (!b->CurrentPanel)b->CurrentPanel = b->Panels.pFirst;
+
+    if (p = b->CurrentPanel){
+        int TitleGap=b->Folded?0:LA_RH;
+        p->X = X + LA_SEAM_W; p->Y = Y + LA_SEAM_W + TitleGap;
+        p->TX = X + LA_SEAM_W; p->TY = Y + LA_SEAM_W + TitleGap;
+        p->TW = W - LA_SEAM_W*2; p->TH = H - LA_SEAM_W*2 - TitleGap;
+        p->Refresh |= LA_TAG_RECALC;
+        p->TitleWidth = tnsStringGetWidth(p->Title->Ptr, 0, 0);
+    }
+}
+void la_UpdateUiPlacement(laWindow *w){
+    laLayout *l;
+    laPanel *p;
+    int CW = w->CW;
+    int CH = w->CH;
+    laBoxedTheme* bt = _LA_THEME_FLOATING_PANEL;
+    int MenuHeight=(bt->TM+bt->BM)*2+LA_RH;
+
+    if(w->MaximizedUi && w->MaximizedUiPanel){
+        w->MaximizedUiPanel->Refresh|=LA_TAG_RECALC;
+    }elif(w->MaximizedBlock){
+        la_RecalcBlockRecursive(w->MaximizedBlock, -LA_SEAM_W, MenuHeight, CW+LA_SEAM_W*2, CH-MenuHeight+LA_SEAM_W);
+    }else{
+        for (l = w->Layouts.pFirst; l; l = l->Item.pNext){
+            la_RecalcBlockRecursive(l->FirstBlock, -LA_SEAM_W, MenuHeight, CW+LA_SEAM_W*2, CH-MenuHeight+LA_SEAM_W);
+        }
+    }
+    for (p = w->Panels.pFirst; p; p = p->Item.pNext){
+        if(p->IsMenuPanel){
+            p->TH=p->H=MenuHeight;
+        }
+        la_EnsurePanelSnapping(p, CW, CH);
+        p->Refresh |= LA_TAG_RECALC;
+    }
+}
+void la_CommandResizeWindow(Window hwnd, int x, int y, int w, int h){
+    laWindow *window = lstFindItem(hwnd, la_IsThisSysWindow, &MAIN.Windows);
+    if (!window) return;
+    
+    XWindowAttributes attr;
+    XGetWindowAttributes(MAIN.dpy, window->win, &attr);
+    window->CW = w; window->CH = h;
+    window->W = w; window->H = h;
+    window->X = x; window->Y = y;
+    la_UpdateUiPlacement(window);
+}
+int la_OnWindowDestroy(Window wnd){
+    laListHandle *hlst = &MAIN.Windows;
+    laWindow *w = lstFindItem(wnd, la_IsThisSysWindow, hlst);
+    if (!w) return;
+
+    if (MAIN.Windows.pFirst==MAIN.Windows.pLast){
+        int empty=0; int mod=laRegisterModifications(1,1,&empty,0);
+        if(mod || empty){ laInvoke(0, "LA_managed_save", 0,0,"on_exit=true;",0); return 0; }
+
+        laShutoff();
+        return 1;
+    }
+
+    laListHandle h={0};laLayout*l=0;
+    while(l=lstPopItem(&w->Layouts)){ lstAppendItem(&h, l); }
+
+    la_DestroyWindow(w);
+
+    int done=0; for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
+        if(done) glXSwapIntervalEXTF(MAIN.dpy, w->win, 0);
+        else { glXSwapIntervalEXTF(MAIN.dpy, w->win, 1); done=1; while(l=lstPopItem(&h)){ lstAppendItem(&w->Layouts, l); } }
+    }
+
+    return 0;
+}
+
+void la_MakeSpecialKeyBit(laEvent *e){
+    e->SpecialKeyBit = MAIN.SpecialKeyStates;
+}
+void la_RegisterSpecialKeys(laEvent* e){
+    if(e->Type&LA_STATE_DOWN){ MAIN.SpecialKeyStates|=e->key&LA_KEY_SPECIALS; }
+    elif(e->Type&LA_STATE_UP){ MAIN.SpecialKeyStates&=~(e->key&LA_KEY_SPECIALS); }
+}
+void la_SaveEvent(Window hwnd, laEvent *e, int use_last_pos){
+    laListHandle *wl = &MAIN.Windows;
+    laListHandle *el = 0;
+    laWindow *wnd = 0;
+
+    wnd = lstFindItem(hwnd, la_IsThisSysWindow, wl);
+    if (!wnd){ FreeMem(e); return; }
+
+    la_MakeSpecialKeyBit(e);
+
+    el = &wnd->EventList;
+    
+    if(use_last_pos){
+        laEvent* last_e=el->pLast;
+        if(last_e){ e->x= last_e->x; e->y= last_e->y; }else {
+            Window root_ret, win_ret; int rrx,rry,rx,ry,rmask;
+            XQueryPointer(MAIN.dpy, hwnd, &root_ret,&win_ret,&rrx,&rry,&rx,&ry,&rmask);
+            e->x = rx; e->y = ry;
+        }
+    }
+    lstAppendItem(el, (laListItem *)e);
+};
+void la_SendKeyboardEvent(Window hwnd, int type, int key){
+    laEvent *e = CreateNew(laEvent);
+    e->Type = type; e->key = key;
+    la_RegisterSpecialKeys(e);
+    printf("%d %lc\n",key,key);
+    la_SaveEvent(hwnd, e, 1);
+};
+void la_SendInputEvent(Window hwnd, uint32_t Input){
+    laEvent *e = CreateNew(laEvent);
+    e->Type = LA_INPUT; e->Input=Input;
+
+    la_SaveEvent(hwnd, e, 1);
+}
+void la_SendEmptyEvent(Window hwnd){
+    laEvent *e = CreateNew(laEvent);
+
+    e->Type = LA_EMPTY;
+
+    la_SaveEvent(hwnd, e, 1);
+}
+void laSendOperatorTriggerEvent(){
+    if (MAIN.ReTriggerOperators) la_SendEmptyEvent(MAIN.CurrentWindow->win);
+    MAIN.ReTriggerOperators = 0;
+}
+int la_TranslateSpecialKey(int keysym){
+    switch(keysym){
+    case XK_Return:    return LA_KEY_ENTER;
+    case XK_BackSpace: return LA_KEY_BACKSPACE;
+    case XK_Delete:    return LA_KEY_DELETE;
+    case XK_Escape:    return LA_KEY_ESCAPE;
+    case XK_Tab:       return LA_KEY_TAB;
+    case XK_Left:      return LA_KEY_ARRLEFT;
+    case XK_Right:     return LA_KEY_ARRRIGHT;
+    case XK_Up:        return LA_KEY_ARRUP;
+    case XK_Down:      return LA_KEY_ARRDOWN;
+    case XK_Control_L: return LA_KEY_CTRL;
+    case XK_Control_R: return LA_KEY_CTRL;
+    case XK_Shift_L:   return LA_KEY_SHIFT;
+    case XK_Shift_R:   return LA_KEY_SHIFT;
+    case XK_Alt_L:     return LA_KEY_ALT;
+    case XK_Alt_R:     return LA_KEY_ALT;
+    default:           return keysym;
+    }
+}
+void la_SendMouseEvent(Window hwnd, int type, int x, int y){
+    laEvent *e = CreateNew(laEvent);
+    e->Type = type;
+    e->x = x;
+    e->y = y;
+    la_SaveEvent(hwnd, e, 0);
+    //printf("mouse %d %d\n", e->x, e->y);
+    //if (e->Type == LA_R_MOUSE_DOWN)
+    //	la_PrintOperatorStack();
+};
+void la_SendTimerEvent(Window hwnd, int type){
+    laEvent *e = CreateNew(laEvent);
+    e->Type = type;
+    la_SaveEvent(hwnd, e, 1);
+};
+void laRetriggerOperators(){
+    MAIN.ReTriggerOperators = 1;
+}
+
+//====================================================================================================
+
+void la_DestroyTheme(laTheme* t){
+    laBoxedTheme*bt; while(bt=lstPopItem(&t->BoxedThemes)){ strSafeDestroy(&bt->Name); *bt->BackRef=0; memFree(bt); }
+    strSafeDestroy(&t->Name);
+    strSafeDestroy(&t->Author);
+}
+laTheme *laDesignTheme(const char *Name, const char *AuthorName){
+    laTheme *t = memAcquireHyper(sizeof(laTheme));
+    strSafeSet(&t->Name, Name);
+    strSafeSet(&t->Author, AuthorName);
+    lstAppendItem(&MAIN.Themes, t);
+    MAIN.CurrentTheme = t;
+    return t;
+}
+laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** BackRef,
+                                 real NormalY,real ActiveY,real BorderY,real TextY,real TextActiveY, real Alpha,
+                                 real LeftMargin,  real RightMargin,  real TopMargin,  real BottomMargin,
+                                 real LeftPadding, real RightPadding, real TopPadding, real BottomPadding){
+    laBoxedTheme *bt = memAcquire(sizeof(laBoxedTheme));
+    strSafeSet(&bt->Name, Name);
+    bt->NormalY=NormalY;
+    bt->ActiveY=ActiveY;
+    bt->BorderY=BorderY;
+    bt->TextY=TextY; bt->TextActiveY=TextActiveY; bt->Alpha = Alpha;
+    bt->Margins[0] = LeftMargin;   bt->Margins[1] = RightMargin;   bt->Margins[2] = TopMargin;   bt->Margins[3] = BottomMargin;
+    bt->Paddings[0] = LeftPadding; bt->Paddings[1] = RightPadding; bt->Paddings[2] = TopPadding; bt->Paddings[3] = BottomPadding;
+    bt->BackRef = BackRef;
+    lstAppendItem(&t->BoxedThemes, bt);
+    return bt;
+}
+laBoxedTheme *laGetTheme(const char *ThemeName){
+    laTheme *t = MAIN.Themes.pFirst;
+    for (t; t; t = t->Item.pNext){
+        laBoxedTheme *bt;
+        if (strSame(t->Name->Ptr, ThemeName)) return t;
+    }
+    return 0;
+}
+laBoxedTheme *laGetBoxedTheme(const char *ThemeName, const char *BoxName){
+    laTheme *t = MAIN.Themes.pFirst;
+    for (t; t; t = t->Item.pNext){
+        laBoxedTheme *bt;
+        if (!strSame(t->Name->Ptr, ThemeName)) continue;
+        bt = t->BoxedThemes.pFirst;
+        for (bt; bt; bt = bt->Item.pNext){
+            if (strSame(bt->Name->Ptr, BoxName)) return bt;
+        }
+    }
+    return 0;
+}
+real* laThemeColor(laBoxedTheme* bt, int which){
+    switch(which){
+        default:
+        case LA_BT_NORMAL: return bt->Normal;
+        case LA_UI_EDITING:
+        case LA_BT_ACTIVE: return bt->Active;
+        case LA_BT_BORDER: return bt->Border;
+        case LA_BT_TEXT:   return bt->Text; break;
+        case LA_BT_TEXT_ACTIVE: return bt->TextActive; break;
+        case LA_BT_DISABLED: return bt->Inactive; break;
+        case LA_BT_DISABLED|LA_BT_TEXT: return bt->TextInactive; break;
+    }
+    return bt->Normal;
+}
+real* laAccentColor(int which){
+    switch(which){
+        default:
+        case LA_BT_NORMAL: case LA_UI_EDITING: case LA_BT_ACTIVE: return MAIN.CurrentTheme->SelectionColor;
+        case LA_BT_BORDER: case LA_BT_TEXT: case LA_BT_TEXT_ACTIVE: return MAIN.CurrentTheme->CursorColor;
+        case LA_BT_VERTEX: return MAIN.CurrentTheme->VertexColor;
+        case LA_BT_FACE:
+        case LA_BT_EDGE: return MAIN.CurrentTheme->EdgeColor;
+        case LA_BT_SVERTEX: return MAIN.CurrentTheme->SVertexColor;
+        case LA_BT_SEDGE: return MAIN.CurrentTheme->SEdgeColor;
+        case LA_BT_SFACE: return MAIN.CurrentTheme->SFaceColor;
+    }
+    return MAIN.CurrentTheme->SelectionColor;
+}
+void la_RefreshBoxedThemeColor(laBoxedTheme* bt){
+    real hcy[3];
+    tnsRGBtoHCY(MAIN.CurrentTheme->Color,hcy);
+    hcy[2]=bt->NormalY; tnsHCYtoRGB(hcy, bt->Normal); bt->Normal[3]=bt->Alpha;
+    hcy[2]=bt->ActiveY; tnsHCYtoRGB(hcy, bt->Active); bt->Active[3]=bt->Alpha;
+    hcy[2]=bt->BorderY; tnsHCYtoRGB(hcy, bt->Border); bt->Border[3]=1;
+    hcy[2]=bt->TextY;   tnsHCYtoRGB(hcy, bt->Text); bt->Text[3]=1;
+    hcy[2]=bt->TextActiveY; tnsHCYtoRGB(hcy, bt->TextActive); bt->TextActive[3]=1;
+    int *tm=&bt->LM,*tp=&bt->LP;
+    for(int i=0;i<4;i++){
+        tm[i]=bt->Margins[i]*LA_RH*MAIN.MarginSize;
+        tp[i]=bt->Paddings[i]*LA_RH*MAIN.MarginSize;
+    }
+}
+void la_RefreshThemeColorSelf(laTheme* th){
+    tnsVectorCopy3d(th->AccentColor, th->CursorColor);   th->CursorColor[3]=th->CursorAlpha;
+    tnsVectorCopy3d(th->AccentColor, th->SelectionColor);th->SelectionColor[3]=th->SelectionAlpha;
+    real hcy[3], usehcy[3];
+    tnsRGBtoHCY(th->Color,hcy); tnsVectorCopy3d(hcy,usehcy);
+    usehcy[2]=th->VertexBrightness; tnsHCYtoRGB(usehcy, th->VertexColor); th->VertexColor[3]=th->VertexTransparency;
+    usehcy[2]=th->EdgeBrightness;   tnsHCYtoRGB(usehcy, th->EdgeColor);   th->EdgeColor[3]=th->EdgeTransparency;
+    tnsVectorCopy3d(th->AccentColor, th->SVertexColor); th->SVertexColor[3]=th->SelectedVertexTransparency;
+    tnsVectorCopy3d(th->AccentColor, th->SEdgeColor); th->SEdgeColor[3]=th->SelectedEdgeTransparency;
+    tnsVectorCopy3d(th->AccentColor, th->SFaceColor); th->SFaceColor[3]=th->SelectedFaceTransparency;
+}
+void la_RefreshThemeColor(laTheme* th){
+    real hcy[3], usehcy[3], normalhcy[3];
+    tnsRGBtoHCY(th->Color,hcy);
+    la_RefreshThemeColorSelf(th);
+    for(laBoxedTheme* bt = th->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){
+        la_RefreshBoxedThemeColor(bt);
+        (*bt->BackRef) = bt;
+        tnsRGBtoHCY(bt->Text, usehcy); usehcy[1]*=th->InactiveSaturation;
+        tnsHCYtoRGB(usehcy, bt->TextInactive); bt->TextInactive[3]=th->InactiveMix;
+        tnsRGBtoHCY(bt->Normal, normalhcy); normalhcy[1]*=th->InactiveSaturation;
+        tnsHCYtoRGB(normalhcy, bt->Inactive); bt->Inactive[3]=bt->Alpha*th->InactiveMix;
+    }
+}
+
+//I FUCKING HATE THIS STUPID FUNCTION
+int la_SetUpUiListMatrix(laUiListDraw *uild, laUiList *Target, int _L, int _R, int LimH, int PanelH, int GlobalX, int GlobalY){
+    laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem));
+    laUiListDrawItem *last = uild->Items.pFirst;
+    int LimW=_R-_L;
+    int SL, SR, SU, SB;
+    int Target__B = Target->B;
+    int Target__R = Target->R;
+
+    uildi->Target = Target;
+
+    //if (Target__B - Target->U > LimH) Target__B = Target->U + LimH;
+    if (Target__R - Target->L > LimW) Target__R = Target->L + LimW;
+
+    uildi->XP = last ? last->XP + Target->PanX : Target->PanX;
+    uildi->YP = last ? last->YP + Target->PanY : Target->PanY;
+
+    uildi->L = last ? Target->L - last->XP : Target->L;
+    uildi->R = last ? Target__R - last->XP : Target__R;
+    uildi->U = last ? Target->U - last->YP : Target->U;
+    uildi->B = last ? Target__B - last->YP : Target__B;
+
+    if (uildi->B - uildi->U > LimH) uildi->B = Target->U + LimH;
+
+    uildi->L -= GlobalX;
+    uildi->R -= GlobalX;
+    uildi->U -= GlobalY;
+    uildi->B -= GlobalY;
+
+    SL = last ? (uildi->L < last->L ? last->L : uildi->L) : uildi->L;
+    SR = last ? (uildi->R > last->R ? last->R : uildi->R) : uildi->R;
+    SU = last ? (uildi->U < last->U ? last->U : uildi->U) : uildi->U;
+    SB = last ? (uildi->B > last->B ? last->B : uildi->B) : uildi->B;
+
+    uildi->DifX = SL - uildi->L;
+    uildi->DifY = SU - uildi->U;
+
+    uildi->L = SL;
+    uildi->R = SR+uildi->DifX;
+    uildi->U = SU;
+    uildi->B = SB;//+uildi->DifY;
+    if(uildi->R>_R){ uildi->R=_R; }
+    if(uildi->B-SU>LimH){ uildi->B=SU+LimH; }
+
+    //printf("py %f %d lb %d b %d limh %d sb%d\n",Target->PanY,uildi->U,last?last->B:0,uildi->B,LimH,SB);
+
+    if(uildi->R - uildi->L<=0 || uildi->B - uildi->U<=0){
+        memFree(uildi);
+        return 0;
+    }
+
+    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);
+    tnsOrtho(Target->L + Target->PanX + uildi->DifX,
+             Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L),
+             Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U),
+             Target->U + Target->PanY + uildi->DifY,
+             -100, 100);
+
+    lstPushItem(&uild->Items, uildi);
+
+    return 1;
+}
+void la_SetUpUiListMatrixInLine(laUiListDraw *uild, int L, int R, int U, int B, int PanX, int PanY, int LimH, int PanelH){
+    laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem));
+    laUiListDrawItem *last = uild->Items.pFirst;
+    int SL, SR, SU, SB;
+
+    if (B - U > LimH) B = U + LimH;
+
+    uildi->XP = last ? last->XP + PanX : PanX;
+    uildi->YP = last ? last->YP + PanY : PanY;
+
+    uildi->L = last ? L - last->XP : L;
+    uildi->R = last ? R - last->XP : R;
+    uildi->U = last ? U - last->YP : U;
+    uildi->B = last ? B - last->YP : B;
+
+    SL = last ? (uildi->L < last->L ? last->L : uildi->L) : uildi->L;
+    SR = last ? (uildi->R > last->R ? last->R : uildi->R) : uildi->R;
+    SU = last ? (uildi->U < last->U ? last->U : uildi->U) : uildi->U;
+    SB = last ? (uildi->B > last->B ? last->B : uildi->B) : uildi->B;
+
+    uildi->DifX = SL - uildi->L;
+    uildi->DifY = SU - uildi->U;
+
+    uildi->L = SL;
+    uildi->R = SR;
+    uildi->U = SU;
+    uildi->B = SB;
+
+    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);
+    tnsOrtho(L + PanX + uildi->DifX,
+             L + PanX + uildi->DifX + (uildi->R - uildi->L),
+             U + PanY + uildi->DifY + (uildi->B - uildi->U),
+             U + PanY + uildi->DifY,
+             -100, 100);
+
+    lstPushItem(&uild->Items, uildi);
+}
+
+void la_RebuildCurrentUiListMatrix(laUiListDraw *uild, laUiList *Target, int LimH, int PanelH){
+    laUiListDrawItem *uildi = uild->Items.pFirst;
+
+    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);
+    tnsOrtho(Target->L + Target->PanX + uildi->DifX,
+             Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L),
+             Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U),
+             Target->U + Target->PanY + uildi->DifY,
+             -100, 100);
+}
+void la_RestoreLastUiListMatrix(laUiListDraw *uild, int PanelH){
+    laUiListDrawItem *uildi = lstPopItem(uild);
+    laUiList *Target;
+
+    memFree(uildi);
+    uildi = uild->Items.pFirst;
+
+    if (!uildi || !uildi->Target){
+        if (uild->Items.pFirst) la_RestoreLastUiListMatrix(uild, PanelH);
+        return;
+    }
+
+    Target = uildi->Target;
+
+    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);
+    tnsOrtho(Target->L + Target->PanX + uildi->DifX,
+             Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L),
+             Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U),
+             Target->U + Target->PanY + uildi->DifY,
+             -100, 100);
+}
+void la_SetupUiListLimitMatrix(laUiListDraw *uild, int L, int R, int U, int B, int PanelH){
+    laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem));
+
+    uildi->L = L;
+    uildi->R = R;
+    uildi->U = U;
+    uildi->B = B;
+
+    tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U);
+    tnsOrtho(L, R, B, U, -100, 100);
+
+    lstPushItem(&uild->Items, uildi);
+}
+void la_ClearUiListMatrix(laUiListDraw *uild){
+    laUiListDrawItem *uildi;
+
+    while (uildi = lstPopItem(uild)){
+        memFree(uildi);
+    }
+}
+
+int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast, laPanel *ParentPanel);
+int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int U, int B, int LimH, int ConditionStackLevel, int GlobalX, int GlobalY, int RegisterNodes);
+void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemoveUser);
+void la_DrawUiListScrollerV(laUiList *uil, int DisplayOffset, int TotalH, int DisplayH, int UiR);
+int la_TestUiListMinumWidth(laUiList *uil);
+
+void la_PanelValidateWidth(laPanel *p, laUiList *ui){
+    if (ui){
+        if (p->MaxW && p->TW > p->MaxW) p->TW = p->MaxW;
+        if (p->MinW && p->TW < p->MinW) p->TW = p->MinW;
+        la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH);
+        p->X = p->TX; p->Y = p->TY;
+        p->W = p->TW;
+    }
+}
+void laEnsurePanelInBound(laPanel *p, laUiList *uil){
+    int cw = MAIN.CurrentWindow->CW;
+    int ch = MAIN.CurrentWindow->CH;
+    int PH = p->TH;
+    laBoxedTheme*bt = *p->BT;
+
+    int uih=uil->B + bt->TM+bt->BM;
+    if (p->BoundUi && !(p->SB||p->ST)) PH = TNS_MAX2(uih, p->MinH);
+    if (p->MaxH && PH > p->MaxH) p->TH = p->MaxH;
+    else if (p->MinH && PH < p->MinH)
+        p->TH = p->MinH;
+    else
+        p->TH = PH;
+
+    p->H = p->TH;
+
+    if ((p->X + p->W) > cw){
+        p->X -= (p->X + p->W - cw);
+    }
+    if ((p->Y + p->H) > ch){
+        p->Y -= (p->Y + p->H - ch);
+    }
+    if (p->X < 0) p->X = 0;
+    if (p->Y < 0) p->Y = 0;
+    if ((p->X + p->W) > cw){
+        p->W -= (p->X + p->W - cw);
+    }
+    if ((p->Y + p->H) > ch){
+        p->H -= (p->Y + p->H - ch);
+    }
+
+    if (p->ST) p->TY = p->ST;
+    if (p->SB && p->TH != ch - p->TY - p->SB) p->Refresh = LA_TAG_RECALC;
+    if (p->SB) p->TH = ch - p->TY - p->SB;
+
+    p->TX = p->X; p->TY = p->Y;
+    p->TW = p->W; p->TH = p->H;
+
+    if (p->OffScr &&
+        (p->W != p->OffScr->pColor[0]->Width ||
+         p->H != p->OffScr->pColor[0]->Height)){
+        tnsConfigureOffscreen(p->OffScr, p->W,p->H);
+    }
+}
+void la_SetPanelMatrix(laPanel *p, laBoxedTheme *bt){
+    tnsDrawToOffscreen(p->OffScr, 1, 0);
+    tnsViewportWithScissor(0, 0, p->W, p->H);
+    //tnsMatrixMode(TNS_PROJECTION_MATRIX);
+    tnsOrtho(0, p->W, p->H, 0, -100, 100);
+}
+void la_SetPanelMatrixDrawWindow(laPanel *p, laBoxedTheme *bt){
+    tnsDrawToScreen();
+    tnsViewportWithScissor(p->X, MAIN.CurrentWindow->CH - p->H - p->Y, p->W, p->H);
+    tnsOrtho(0, p->W, p->H, 0, -100, 100);
+}
+void la_SetPanelMatrixLRTB(int PW, int PH, int LPadding, int RPadding, int TPadding, int BPadding, int XOffset, int YOffset){
+    tnsViewportWithScissor(LPadding, BPadding, PW - LPadding - RPadding, PH - TPadding - BPadding);
+    tnsOrtho(XOffset, XOffset + PW - LPadding - RPadding, YOffset + PH - BPadding, YOffset + TPadding, -100, 100);
+}
+void la_PanelBackgroundInit(laPanel *p, laBoxedTheme *bt){
+    glClearColor(LA_COLOR4(laThemeColor(bt,LA_BT_NORMAL)));
+    tnsClearAll();
+}
+void la_PanelDrawToWindow(laPanel *p, laWindow *w){
+    real Color[] = {1, 1, 1, 1};
+    real L, W, U, H;
+    switch (p->AnimationMode){
+    case 0:
+        tnsDraw2DTextureDirectly(p->OffScr->pColor[0], p->X, p->Y, p->W, p->H);
+        //if(p->Mode==LA_PANEL_FLOATING_TOP)
+        //    tnsDrawStringAuto("◿",laThemeColor(*p->BT,LA_BT_BORDER),p->X+p->W-LA_RH, p->X+p->W, p->H+p->Y-LA_RH, LA_TEXT_ALIGN_CENTER);
+        break;
+
+    case LA_PANEL_ANIMATION_DROP_DOWN:
+        tnsVectorMultiSelf4d(Color, p->AnimationRatio);
+        tnsDraw2DTextureArg(
+            p->OffScr->pColor[0],
+            p->X, p->Y, p->W, p->H * p->AnimationRatio,
+            Color,
+            0, 0, 1 - p->AnimationRatio, 0);
+        p->AnimationRatio += (1 - p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;
+        if (p->AnimationRatio > 0.99) p->AnimationMode = 0;
+        break;
+
+    case LA_PANEL_ANIMATION_EXPAND:
+        L = tnsLinearItp(p->X, p->X + p->W, 0.3);
+        U = tnsLinearItp(p->Y, p->Y + p->H, 0.3);
+        W = tnsLinearItp(0, p->W, 0.4);
+        H = tnsLinearItp(0, p->H, 0.4);
+        tnsVectorMultiSelf4d(Color, p->AnimationRatio);
+        tnsDraw2DTextureArg(
+            p->OffScr->pColor[0],
+            tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),
+            tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),
+            Color,
+            0, 0, 0, 0);
+        p->AnimationRatio += (1 - p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;
+        if (p->AnimationRatio > 0.99) p->AnimationMode = 0;
+        break;
+
+    case LA_PANEL_ANIMATION_DISSOVE:
+        L = tnsLinearItp(p->X, p->X + p->W, -0.2);
+        U = tnsLinearItp(p->Y, p->Y + p->H, -0.2);
+        W = tnsLinearItp(0, p->W, 1.4);
+        H = tnsLinearItp(0, p->H, 1.4);
+        tnsVectorMultiSelf4d(Color, (p->AnimationRatio));
+        if (p->OffScr) tnsDraw2DTextureArg(
+                p->OffScr->pColor[0],
+                tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),
+                tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),
+                Color,
+                0, 0, 0, 0);
+        p->AnimationRatio -= (p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;
+        if (p->AnimationRatio < 0.01) p->AnimationMode = 0;
+        break;
+
+    case LA_PANEL_ANIMATION_COLLAPSE:
+        L = tnsLinearItp(p->X, p->X + p->W, 0.3);
+        U = tnsLinearItp(p->Y, p->Y + p->H, 0.3);
+        W = tnsLinearItp(0, p->W, 0.4);
+        H = tnsLinearItp(0, p->H, 0.4);
+        tnsVectorMultiSelf4d(Color, p->AnimationRatio);
+        if (p->OffScr) tnsDraw2DTextureArg(
+                p->OffScr->pColor[0],
+                tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),
+                tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),
+                Color,
+                0, 0, 0, 0);
+        p->AnimationRatio -= p->AnimationRatio * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;
+        if (p->AnimationRatio < 0.01) p->AnimationMode = 0;
+        break;
+
+    case LA_PANEL_ANIMATION_MINIMIZE:
+        L = tnsLinearItp(0, p->X, 0.3);
+        U = tnsLinearItp(w->H, p->Y + p->H, 0.3);
+        W = tnsLinearItp(0, p->W, 0.4);
+        H = tnsLinearItp(0, p->H, 0.4);
+        tnsVectorMultiSelf4d(Color, p->AnimationRatio);
+        tnsDraw2DTextureArg(
+            p->OffScr->pColor[0],
+            tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio),
+            tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio),
+            Color,
+            0, 0, 0, 0);
+        p->AnimationRatio -= p->AnimationRatio * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60;
+        if (p->AnimationRatio < 0.01) p->AnimationMode = 0;
+        break;
+    }
+
+    tnsFlush();
+}
+void la_PanelDrawToOffsceen(laPanel *p, laUiList *uil){
+    laEnsurePanelInBound(p,p->MenuRefer?p->MenuRefer:&p->UI);
+    if (!p->OffScr){
+        p->OffScr = tnsCreate2DOffscreen(GL_RGBA8, p->W, p->H, MAIN.PanelMultisample, 0);
+    }
+    tnsDrawToOffscreen(p->OffScr, 1, 0);
+}
+void la_PanelRefreshDetachedProp(laPanel *panel){
+    laProp *p;
+    for (p = panel->PropLinkContainer->Props.pFirst; p; p = p->Item.pNext){la_StopUsingPropPack(&p->DetachedPP);
+        la_StepPropPack(&p->DetachedPP);
+        la_UsePropPack(&p->DetachedPP, 0);
+        //if (p->DetachedPP.LastPs && p->DetachedPP.LastPs->p->Container ? p->DetachedPP.LastPs->p->Container->Hyper : 0){
+        //    laUseDataBlock(
+        //        p->DetachedPP.LastPs->UseInstance,
+        //        p->DetachedPP.LastPs->p,
+        //        MAIN.PropMatcherContextP->FrameDistinguish,
+        //        MAIN.PropMatcherContextP,
+        //        la_PropPanelUserRemover, 0);
+        //}
+    }
+}
+
+void la_PanelDrawDescendBorder(laPanel *Panel, laBoxedTheme *bt, int Width, real Alpha){
+    real* color=laThemeColor(bt,LA_BT_NORMAL);
+    tnsColor4d(LA_COLOR3(color),Alpha);
+    tnsVertex2d(Panel->X + Width, Panel->Y + Panel->H);
+    tnsVertex2d(Panel->X + Width, Panel->Y + Panel->H + Width);
+    tnsVertex2d(Panel->X + Panel->W, Panel->Y + Panel->H);
+    tnsVertex2d(Panel->X + Panel->W + Width, Panel->Y + Panel->H + Width);
+    tnsVertex2d(Panel->X + Panel->W, Panel->Y + Width);
+    tnsVertex2d(Panel->X + Panel->W + Width, Panel->Y + Width);
+    tnsPackAs(GL_TRIANGLE_STRIP);
+
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertex2d(Panel->X, Panel->Y);
+    tnsVertex2d(Panel->X, Panel->Y + Panel->H);
+    tnsVertex2d(Panel->X + Panel->W, Panel->Y + Panel->H);
+    tnsVertex2d(Panel->X + Panel->W, Panel->Y);
+    tnsPackAs(GL_LINE_LOOP);
+}
+
+int la_AnimateUiListRecursive(laUiList *uil);
+
+void la_PanelDefDraw(laWindow *w, laPanel *p, laBoxedTheme *bt){
+    int DrawState_ = 0;
+    laUiListDraw uild = {0};
+
+    if (p->Show){
+        la_SetPropMathcerContext(p);
+        MAIN.CurrentPanel = p;
+
+        //if(p->Refresh&(LA_TAG_REDRAW|LA_TAG_RECALC)){
+        //    printf("Draw %0xld (%s)\n", p, p->Title?p->Title->Ptr:0);
+        //}
+
+        if (p->Refresh & LA_TAG_RECALC){
+            laRecalcPanelImmediate(p);
+        }
+        if (!p->MenuRefer){
+            if(!p->OffScr){la_PanelDrawToOffsceen(p,&p->UI); p->Refresh|=LA_TAG_REDRAW;}
+            if (p->Refresh || !p->OffScr){
+                la_PanelDrawToOffsceen(p, &p->UI);
+                la_SetupUiListLimitMatrix(&uild, 0, p->W, 0, p->H, p->H);
+                la_PanelBackgroundInit(p, bt);
+                la_DrawUiListScrollerV(&p->UI, p->UI.PanY, p->UI.B-p->UI.U-bt->TM-bt->BM, p->H-p->TitleBar.B-bt->TM-bt->BM*2, p->W);
+                tnsFlush();
+
+                if(((p->UI.B>p->H) && (!p->UI.ScrollerShownV))||
+                    ((p->UI.B<=p->H) && p->UI.ScrollerShownV)){
+                    p->UI.ScrollerShownV=!p->UI.ScrollerShownV;
+                    DrawState_++;
+                }
+                if(p->UI.PanY && p->UI.B-p->UI.PanY<p->H-bt->BM ){
+                    p->UI.PanY = (p->UI.B-p->H/*-bt->BM-bt->TM*/-p->TitleBar.B);
+                    if(p->UI.PanY<0){p->UI.PanY=0;}
+                    DrawState_++;
+                }
+
+                if(p->Refresh&LA_TAG_RECALC_SCROLLER) DrawState_++;
+
+                if (!la_AnimateUiListRecursive(&p->TitleBar)) p->Refresh = 0;
+                else p->Refresh = LA_TAG_ANIMATION;
+                if (!la_AnimateUiListRecursive(&p->UI)) p->Refresh = p->Refresh;
+                else p->Refresh = LA_TAG_ANIMATION;
+                DrawState_ += la_DrawUiListRecursive(&uild, &p->TitleBar, 0, p->W, 0, p->H, 10000, -1, 0, 0, 0);
+                if(p!=w->MaximizedUiPanel){
+                    DrawState_ += la_DrawUiListRecursive(&uild, &p->UI, 0, p->W, 0, p->H, 10000, -1, 0, 0, 0);
+                }else{
+                    tnsViewportWithScissor(0,0,p->W,p->H); tnsOrtho(0,p->W,p->H,0,-100,100);
+                    tnsDrawStringAutoM("Canvas is maximized",0,laThemeColor(bt,LA_BT_TEXT),
+                        bt->LM,p->W-bt->RM,(p->H - p->TitleBar.B)/2+LA_RH2,LA_TEXT_ALIGN_CENTER|LA_TEXT_LINE_WRAP);
+                    tnsFlush();
+                }
+                if (DrawState_) p->Refresh = LA_TAG_RECALC;
+            }
+        }else{
+            if (p->Refresh || !p->OffScr){
+                la_PanelDrawToOffsceen(p, p->MenuRefer);
+                la_SetupUiListLimitMatrix(&uild, 0, p->W, 0, p->H, p->H);
+                la_PanelBackgroundInit(p, bt);
+                la_DrawUiListScrollerV(p->MenuRefer, p->MenuRefer->PanY,
+                    p->MenuRefer->B-p->MenuRefer->U-bt->TM-bt->BM, p->H-bt->TM-bt->BM*2, p->W);
+                    tnsFlush();
+
+                if(((p->MenuRefer->TB>p->H-bt->BP) && (!p->MenuRefer->ScrollerShownV))||
+                    ((p->MenuRefer->TB<=p->H-bt->BP) && p->MenuRefer->ScrollerShownV)){
+                    p->MenuRefer->ScrollerShownV=!p->MenuRefer->ScrollerShownV;
+                    DrawState_++;
+                }
+                if(p->UI.PanY && p->MenuRefer->B-p->MenuRefer->PanY<p->H-bt->BM){
+                    p->MenuRefer->PanY = (p->MenuRefer->B-p->H-bt->BM);
+                    if(p->MenuRefer->PanY<0){p->MenuRefer->PanY=0;}
+                    DrawState_++;
+                }
+
+                if(p->Refresh&LA_TAG_RECALC_SCROLLER) DrawState_++;
+
+                if (!la_AnimateUiListRecursive(p->MenuRefer)) p->Refresh = 0;
+                else p->Refresh = LA_TAG_ANIMATION;
+                DrawState_ += la_DrawUiListRecursive(&uild, p->MenuRefer, 0, p->W, 0, p->H, 10000, -1, 0, 0, 0);
+                if (DrawState_) p->Refresh = LA_TAG_RECALC;
+            }
+        }
+
+        tnsDrawToScreen();
+        tnsViewportWithScissor(0, 0, w->CW, w->CH);
+        tnsOrtho(0, w->CW, w->CH, 0, -100, 100);
+
+        la_PanelDrawToWindow(p, w);
+
+        if (p->Mode && (!p->AnimationMode || (p->AnimationMode && p->AnimationRatio > 0.99))){
+            tnsUseNoTexture();
+            if (!p->IsMenuPanel){
+                la_PanelDrawDescendBorder(p, bt, MAIN.SolidShadowLength, MAIN.FloatingAlpha);
+            }
+            tnsFlush();
+        }
+    }elif (p->AnimationMode){
+        la_PanelDrawToWindow(p, w);
+    }
+}
+void la_AttachedPanelDefDraw(laWindow* w, laPanel* p, laBoxedTheme* bt){
+    if(!p->Show && p!=w->MaximizedUiPanel) return;
+    if (p->SubPanels.pLast && (p->LaterDestroy ? !p->AnimationMode : 1)){
+        laPanel *pi, *PrevPI;
+        for (pi = p->SubPanels.pLast; pi; pi = PrevPI){
+            PrevPI = pi->Item.pPrev;
+            if (pi->AnimationMode && pi->LaterDestroy){
+                lstRemoveItem(&p->SubPanels, pi);
+                lstAppendItem(&MAIN.CurrentWindow->FadingPanels, pi);
+                continue;
+            }
+            la_PanelDefDraw(w, pi, _LA_THEME_FLOATING_PANEL);
+            la_AttachedPanelDefDraw(w,pi,bt);
+        }
+    }
+}
+void la_BlockDrawDropLocations(laBlock *b, int CH, real *BorderColor4dV, real *FillColor4dv){
+    real PanelSquare[] = {
+        b->X + 2, CH - (b->Y + 2 + LA_RH),
+        b->X + 2, CH - (b->Y + b->H - 4),
+        b->X + b->W - 4, CH - (b->Y + b->H - 4),
+        b->X + b->W - 4, CH - (b->Y + 2 + LA_RH)};
+    real Center[] = {
+        tnsLinearItp(PanelSquare[0], PanelSquare[4], 0.5), tnsLinearItp(PanelSquare[1], PanelSquare[5], 0.5)};
+    real DraggingPlot[] = {
+        tnsLinearItp(PanelSquare[0], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[1], Center[1], 0.5),
+        PanelSquare[0],
+        PanelSquare[1],
+        tnsLinearItp(PanelSquare[2], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[3], Center[1], 0.5),
+        PanelSquare[2],
+        PanelSquare[3],
+        tnsLinearItp(PanelSquare[4], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[5], Center[1], 0.5),
+        PanelSquare[4],
+        PanelSquare[5],
+        tnsLinearItp(PanelSquare[6], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[7], Center[1], 0.5),
+        PanelSquare[6],
+        PanelSquare[7],
+    };
+    real Square[] = {
+        tnsLinearItp(PanelSquare[0], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[1], Center[1], 0.5),
+        tnsLinearItp(PanelSquare[2], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[3], Center[1], 0.5),
+        tnsLinearItp(PanelSquare[4], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[5], Center[1], 0.5),
+        tnsLinearItp(PanelSquare[6], Center[0], 0.5),
+        tnsLinearItp(PanelSquare[7], Center[1], 0.5),
+    };
+    real PlotColor[] = {LA_COLOR3(BorderColor4dV), 0.8,
+        LA_COLOR3(BorderColor4dV), 0,
+        LA_COLOR3(BorderColor4dV), 0.8,
+        LA_COLOR3(BorderColor4dV), 0,
+        LA_COLOR3(BorderColor4dV), 0.8,
+        LA_COLOR3(BorderColor4dV), 0,
+        LA_COLOR3(BorderColor4dV), 0.8,
+        LA_COLOR3(BorderColor4dV), 0,
+    };
+    real FillColor[] = {LA_COLOR3(FillColor4dv), 0.8,
+        LA_COLOR3(FillColor4dv), 0,
+        LA_COLOR3(FillColor4dv), 0.8,
+        LA_COLOR3(FillColor4dv), 0,
+        LA_COLOR3(FillColor4dv), 0.8,
+        LA_COLOR3(FillColor4dv), 0,
+        LA_COLOR3(FillColor4dv), 0.8,
+        LA_COLOR3(FillColor4dv), 0,
+    };
+
+    tnsUseNoTexture();
+
+    if (MAIN.CurrentWindow->CurrentLayout->DropToBlock == b){
+        int Index[4];
+        tnsVertexArray2d(DraggingPlot, 8);
+        tnsColorArray4d(FillColor, 8);
+        switch (MAIN.CurrentWindow->CurrentLayout->DropLocation){
+        case 0:
+            Index[0] = 0; Index[1] = 2; Index[2] = 4; Index[3] = 6;
+            break;
+        case LA_BLOCK_DROP_LOCATION_L:
+            Index[0] = 0; Index[1] = 1; Index[2] = 3; Index[3] = 2;
+            break;
+        case LA_BLOCK_DROP_LOCATION_R:
+            Index[0] = 4; Index[1] = 5; Index[2] = 7; Index[3] = 6;
+            break;
+        case LA_BLOCK_DROP_LOCATION_U:
+            Index[0] = 0; Index[1] = 1; Index[2] = 7; Index[3] = 6;
+            break;
+        case LA_BLOCK_DROP_LOCATION_B:
+            Index[0] = 4; Index[1] = 5; Index[2] = 3; Index[3] = 2;
+            break;
+        }
+        //glDisable(GL_CULL_FACE);
+        tnsIndexArray(Index, 4);
+        tnsPackAs(GL_TRIANGLE_FAN);
+        //tnsFlush();
+    }
+
+    tnsVertexArray2d(DraggingPlot, 8);
+    tnsColorArray4d(PlotColor, 8);
+    tnsPackAs(GL_LINES);
+
+    tnsVertexArray2d(Square, 4);
+    tnsColor4dv(BorderColor4dV);
+    tnsPackAs(GL_LINE_LOOP);
+
+    glLineWidth(LA_SEAM_W);
+    tnsFlush();
+    glLineWidth(1);
+}
+void la_BlockDefDrawSelf(laBlock *b, int CH){
+    laBoxedTheme *bt = _LA_THEME_TAB;
+    laPanel *p;
+    real v[] = {
+        b->X, CH - b->Y,
+        b->X + LA_SEAM_W, CH - b->Y ,
+        b->X, CH - (b->Y + b->H),
+        b->X + LA_SEAM_W, CH - (b->Y + b->H - LA_SEAM_W),
+        b->X + b->W, CH - (b->Y + b->H),
+        b->X + b->W - LA_SEAM_W, CH - (b->Y + b->H - LA_SEAM_W),
+        b->X + b->W, CH - b->Y,
+        b->X + b->W - LA_SEAM_W, CH - b->Y};
+    real tv[8];
+    real ratio = 1.0001f;
+    int tw = 0;
+    int L = LA_RH+LA_SEAM_W;
+
+    for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+        tw += p->TitleWidth + LA_SEAM_W*2;
+    }
+    if (tw > b->W - LA_SEAM_W*2 - LA_RH) ratio = (real)(b->W - LA_SEAM_W*2 - LA_RH) / (real)tw;
+
+    tnsUseNoTexture();
+    tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE));
+    tnsVertexArray2d(v, 8);
+    tnsPackAs(GL_TRIANGLE_STRIP);
+
+    int TitleGap=b->Folded?0:LA_RH;
+
+    tnsMakeQuad2d(tv, b->X, (CH - b->Y),
+                    b->X + b->W, (CH - b->Y),
+                    b->X + b->W, (CH - b->Y - TitleGap),
+                    b->X, (CH - b->Y - TitleGap));
+    tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE));
+    tnsVertexArray2d(tv, 4);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    tnsMakeQuad2d(tv,b->X + LA_SEAM_W, (CH - b->Y - TitleGap),
+                    b->X + b->W - LA_SEAM_W, (CH - b->Y - TitleGap),
+                    b->X + b->W - LA_SEAM_W, (CH - b->Y - TitleGap - LA_SEAM_W),
+                    b->X + LA_SEAM_W, (CH - b->Y - TitleGap- LA_SEAM_W));
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertexArray2d(tv, 4);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    if(b->Folded){
+        real Color[4]; tnsVectorCopy4d(laThemeColor(bt,LA_BT_BORDER), Color); Color[3]*=b->OnButton==2?1:(b->OnButton==1?0.3:0);
+        tnsDrawStringAuto("⯆",Color, b->X+LA_SEAM_W,b->X+LA_SEAM_W+LA_RH, CH-b->Y, LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER);
+        tnsDrawStringAuto("⮼",Color, b->X+LA_SEAM_W+LA_RH,b->X+LA_SEAM_W+LA_2RH, CH-b->Y, LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER);
+        tnsFlush(); return; 
+    }
+
+    int LT=0,RT=0;
+    for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+        RT = LT + p->TitleWidth + LA_SEAM_W*2;
+        tnsMakeQuad2d(tv,b->X + L+LT * ratio, (CH - b->Y),
+                         b->X + L+RT * ratio, (CH - b->Y),
+                         b->X + L+RT * ratio, (CH - b->Y - LA_RH),
+                         b->X + L+LT * ratio, (CH - b->Y - LA_RH));
+
+        if (p == b->CurrentPanel){
+            tnsUseNoTexture();
+            tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+            tnsVertexArray2d(tv, 4);
+            tnsPackAs(GL_TRIANGLE_FAN);
+            tnsDrawStringAuto(p->Title->Ptr, laThemeColor(bt,LA_BT_TEXT_ACTIVE), b->X + L +LT* ratio + LA_SEAM_W, b->X + L +RT* ratio, CH - b->Y, LA_TEXT_REVERT_Y);
+        }else{
+            tnsDrawStringAuto(p->Title->Ptr, laThemeColor(bt,LA_BT_TEXT), b->X + L +LT* ratio + LA_SEAM_W, b->X + L +RT* ratio, CH - b->Y, LA_TEXT_REVERT_Y);
+        }
+
+        LT =RT;
+    }
+
+    tnsDrawStringAuto("🔻",laThemeColor(bt,LA_BT_BORDER), b->X+LA_SEAM_W,b->X+b->W, CH-b->Y, LA_TEXT_REVERT_Y);
+
+    tnsFlush();
+}
+void la_BlockDefDrawSelfEmpty(laBlock *b, int CH){
+    laBoxedTheme *bt = _LA_THEME_PANEL;
+    real tv[8];
+    tnsUseNoTexture();
+    tnsMakeQuad2d(tv, b->X, (CH - b->Y),
+                      b->X + b->W, (CH - b->Y),
+                      b->X + b->W, (CH - b->Y-b->H),
+                      b->X, (CH - b->Y-b->H));
+    tnsVertexArray2d(tv, 4);
+    tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    tnsDrawStringAuto("Dock some panels here.", laThemeColor(bt,LA_BT_TEXT), b->X+LA_SEAM_W,b->X+b->W-LA_SEAM_W, CH-b->Y-b->H/2+LA_RH2,
+        LA_TEXT_ALIGN_CENTER|LA_TEXT_REVERT_Y|LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP);
+    tnsFlush();
+}
+void la_BlockDefDrawRecursive(laWindow *w, laBoxedTheme *bt, laBlock *b){
+    if (b->B1){
+        la_BlockDefDrawRecursive(w, bt, b->B1);
+        la_BlockDefDrawRecursive(w, bt, b->B2);
+    }elif (b->CurrentPanel /*&& b->CurrentPanel->Refresh*/){
+        if (!b->CurrentPanel->BT) b->CurrentPanel->BT = &_LA_THEME_PANEL;
+        la_PanelDefDraw(w, b->CurrentPanel, *b->CurrentPanel->BT);
+        tnsViewportWithScissor(0, 0, w->CW, w->CH);
+        tnsOrtho(0, w->CW, 0, w->CH, -100, 100);
+        la_BlockDefDrawSelf(b, w->CH);
+    }else{
+        tnsViewportWithScissor(0, 0, w->CW, w->CH);
+        tnsOrtho(0, w->CW, 0, w->CH, -100, 100);
+        la_BlockDefDrawSelfEmpty(b, w->CH);
+    }
+
+
+    if(b==MAIN.CurrentWindow->CurrentLayout->MovingBlock){
+        tnsUseNoTexture();
+        int at; real tv[8];
+        if (b->Vertical){
+            at = b->H * b->SplitRatio + b->Y;
+            tnsMakeQuad2d(tv,b->X, (w->CH - at + LA_SEAM_W),
+                            b->X + b->W, (w->CH - at + LA_SEAM_W),
+                            b->X + b->W, (w->CH - at - LA_SEAM_W),
+                            b->X, (w->CH - at - LA_SEAM_W));
+        }else{
+            at = b->X + b->W * b->SplitRatio;
+            tnsMakeQuad2d(tv,at+ LA_SEAM_W, (w->CH - b->Y),
+                            at- LA_SEAM_W, (w->CH - b->Y),
+                            at- LA_SEAM_W, (w->CH - b->Y - b->H),
+                            at+ LA_SEAM_W, (w->CH - b->Y - b->H));
+        }
+        tnsColor4dv(laThemeColor(_LA_THEME_TAB,LA_BT_BORDER));
+        tnsVertexArray2d(tv, 4);
+        tnsPackAs(GL_TRIANGLE_FAN);
+    }
+    //la_SetPanelMatrixDrawWindow(b->CurrentPanel, *b->CurrentPanel->BT);
+    tnsFlush();
+}
+void la_BlockDefDrawAttachedRecursive(laWindow *w, laBoxedTheme *bt, laBlock *b){
+    if (b->B1){
+        la_BlockDefDrawAttachedRecursive(w, bt, b->B1);
+        la_BlockDefDrawAttachedRecursive(w, bt, b->B2);
+    }elif (b->CurrentPanel /*&& b->CurrentPanel->Refresh*/){
+        la_AttachedPanelDefDraw(w,b->CurrentPanel,*b->CurrentPanel->BT);
+    }
+    tnsFlush();
+}
+
+void la_ClearBlockFramebuffersRecursive(laBlock* b, int AlsoClearCurrent){
+    if(b->B1)la_ClearBlockFramebuffersRecursive(b->B1,AlsoClearCurrent);
+    if(b->B2)la_ClearBlockFramebuffersRecursive(b->B2,AlsoClearCurrent);
+    for(laPanel* p=b->Panels.pFirst;p;p=p->Item.pNext){
+        if(!AlsoClearCurrent && p==b->CurrentPanel) continue;
+        if(p->OffScr){
+            tnsDelete2DOffscreen(p->OffScr); p->OffScr=0;
+        }
+    }
+}
+void la_ClearUnusedFramebuffers(laWindow* w){
+    for(laLayout* l = w->Layouts.pFirst;l;l=l->Item.pNext){
+        la_ClearBlockFramebuffersRecursive(l->FirstBlock, l!=w->CurrentLayout);
+    }
+    for(laPanel* p=w->Panels.pFirst;p;p=p->Item.pNext){
+        if(p->Show || p->AnimationMode) continue;
+        if(p->OffScr){
+            tnsDelete2DOffscreen(p->OffScr); p->OffScr=0;
+        }
+    }
+}
+
+void la_WindowDefDraw(laWindow *w, laBoxedTheme *bt){
+    laPanel *p, *NextP;
+    laLayout *l = w->CurrentLayout;
+
+    la_ClearUnusedFramebuffers(w);
+
+    tnsDrawToScreen();
+
+    tnsViewportWithScissor(0, 0, w->CW, w->CH);
+    glClearColor(0.2, 0.2, 0.3, 1.0);
+    tnsClearAll();
+
+    tnsUseNoTexture();
+    if (l->Draw) l->Draw(w, l);
+
+    tnsResetModelMatrix();tnsResetProjectionMatrix();tnsResetViewMatrix();
+    //tnsShadeMode(GL_SMOOTH);
+
+    glEnable(GL_BLEND);
+    //lBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA);
+
+    laUiItem* ui;
+    if((ui=w->MaximizedUi) && w->MaximizedUiPanel && ui->Type->Draw && ui->CanvasTemplate->SecondDraw){
+        MAIN.CurrentPanel=w->MaximizedUiPanel; laPanel* p=w->MaximizedUiPanel; int DrawState_=0;
+        if(p->Refresh){
+            if(p->Refresh&LA_TAG_RECALC){
+                la_SetPropMathcerContext(p);
+                laRecalcPanelImmediate(p);
+            }
+            ui->Type->Draw(ui, LA_RH); tnsFlush();
+            if (!la_AnimateUiListRecursive(&p->UI)) p->Refresh = 0;
+            else p->Refresh|=LA_TAG_ANIMATION;
+        }
+        tnsDrawToScreen();
+        tnsResetViewMatrix();
+        tnsViewportWithScissor(0, 0, w->CW, w->CH);
+        tnsOrtho(0, w->CW, w->CH, 0, -100, 100);
+        ui->CanvasTemplate->SecondDraw(ui, LA_RH);
+        tnsFlush();
+        if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){
+            laUiListDraw uild = {0}; for (laUiList* sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                tnsFlush();
+                DrawState_+=la_DrawUiListRecursive(&uild, sub, ui->L, ui->R, ui->U, ui->B, 10000, 0, 0, 0, 0);
+            }
+        }
+        if (DrawState_) p->Refresh = LA_TAG_RECALC;
+    }else{
+        laBlock* RootBlock= w->MaximizedBlock?w->MaximizedBlock:l->FirstBlock;
+        la_BlockDefDrawRecursive(w, bt, RootBlock);
+        la_BlockDefDrawAttachedRecursive(w,bt, RootBlock);
+    }
+
+    for (p = w->Panels.pLast; p; p = NextP){
+        NextP = p->Item.pPrev;
+        if (!p->BT) p->BT = &_LA_THEME_FLOATING_PANEL;
+
+        if (p->AnimationMode && p->LaterDestroy){
+            lstRemoveItem(&w->Panels, p);
+            lstAppendItem(&MAIN.CurrentWindow->FadingPanels, p);
+            continue;
+        }
+
+        la_PanelDefDraw(w, p, *p->BT);
+    }
+
+    for(laPanel* p=w->Panels.pFirst;p;p=p->Item.pNext){
+        la_AttachedPanelDefDraw(w,p,*p->BT);
+    }
+
+    if (MAIN.CurrentWindow->CurrentLayout->DropToBlock){
+        laBoxedTheme* ubt=_LA_THEME_TAB;tnsUseNoTexture();
+        tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, 0, w->CH, -100, 100);
+        la_BlockDrawDropLocations(MAIN.CurrentWindow->CurrentLayout->DropToBlock,
+            MAIN.CurrentWindow->CH, laThemeColor(ubt,LA_BT_ACTIVE), laThemeColor(ubt,LA_BT_BORDER));
+        tnsFlush();
+    }
+
+    for (p = w->FadingPanels.pLast; p; p = NextP){
+        NextP = p->Item.pNext;
+        if (!p->AnimationMode){
+            lstRemoveItem(&w->FadingPanels, p);
+            p->AnimationMode = LA_PANEL_ANIMATION_DESTROY;
+            laDeferredDestroyPanel(p);
+        }else
+            la_PanelDrawToWindow(p, w);
+    }
+}
+int laStartWindow(laWindow *w){
+    //ShowWindow(w->win, SW_SHOWNORMAL);
+    glXMakeContextCurrent(MAIN.dpy, w->win,w->win, MAIN.glc);
+    MAIN.CurrentWindow = w;
+    if(!w->CurrentLayout){
+        if(!w->Layouts.pFirst){laDesignLayout(w, "Empty Layout");}
+        w->CurrentLayout=w->Layouts.pFirst;
+    }
+    laInvokeUi(0, "LA_window_operator", 0, w, 0, 0);
+    w->Shown = 1;
+}
+void la_AssignWindowPP(laWindow* w){
+    w->PP.EndInstance = w;
+    w->PP.LastPs = &w->FakePS;
+    w->PP.LastPs->p = _LA_PROP_WINDOW;
+    w->PP.LastPs->UseInstance = w;
+    w->PP.LastPs->Type = L'.';
+}
+laWindow *laDesignWindow(int X, int Y, int W, int H){
+    laWindow *n = memAcquireHyper(sizeof(laWindow));
+
+    strSafeSet(&n->Title, "Empty Window");
+    n->X = X; n->Y = Y; n->W = W; n->H = H;
+
+    la_CreateSystemWindow(n, MAIN.Windows.pFirst!=0);
+
+    lstAppendItem(&MAIN.Windows, n);
+    MAIN.CurrentWindow = n;
+
+    la_AssignWindowPP(n);
+    laui_DefaultMenuBar(n);
+
+    return n;
+}
+void laSetWindowCursor(int id){
+    //SetClassLongPtr(MAIN.CurrentWindow->win,
+    //                GCLP_HCURSOR, LoadCursor(NULL, la_ConvertCursorID(id)));
+};
+void la_AssignBlockPP(laBlock* b){
+    b->PP.EndInstance = b;
+    b->PP.LastPs = &b->FakePS;
+    b->PP.LastPs->p = _LA_PROP_BLOCK;
+    b->PP.LastPs->UseInstance = b;
+    b->PP.LastPs->Type = L'.';
+}
+laLayout *laDesignLayout(laWindow *w, char *Title){
+    laLayout *l = memAcquireHyper(sizeof(laLayout));
+
+    l->FirstBlock = memAcquire(sizeof(laBlock));
+    la_AssignBlockPP(l->FirstBlock);
+
+    lstAppendItem(&w->Layouts, l);
+    strSafeSet(&l->ID, Title);
+
+    w->CurrentLayout = l;
+    laRenameWindow(w, Title);
+
+    return l;
+}
+void laFoldBlockTitle(laBlock* b){ if(b->B1) return; b->Folded=1; la_RecalcBlockRecursive(b,b->X,b->Y,b->W,b->H); }
+void laUnfoldBlockTitle(laBlock* b){ if(b->B1) return; b->Folded=0; b->OnButton=0; la_RecalcBlockRecursive(b,b->X,b->Y,b->W,b->H); }
+void laMaximizeBlock(laBlock* b){ if(b->B1) return; laWindow* w=MAIN.CurrentWindow;
+    if(w->MaximizedBlock==b){laRestoreToLayout(); return;} w->MaximizedBlock=b; la_UpdateUiPlacement(w);
+    laNotifyUsers("la.windows.maximized_block"); }
+void laRestoreToLayout(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedBlock) return;  w->MaximizedBlock=0; la_UpdateUiPlacement(w);
+    laNotifyUsers("la.windows.maximized_block"); }
+void laMaximizeCanvasUI(laUiItem* ui, laPanel* UiParentPanel){
+    laRestoreCanvasUI();
+    if(!ui->Type||(!(ui->Type->Tag&LA_UI_TAG_IS_OFFSCREEN))||!UiParentPanel) return;
+    la_StopUiOperatorService(UiParentPanel); la_StopUiOperatorService(ui); laRetriggerOperators();
+    laWindow* w=MAIN.CurrentWindow; w->MaximizedUi=ui; w->MaximizedUiPanel=UiParentPanel; UiParentPanel->Refresh |= LA_TAG_RECALC;
+    UiParentPanel->Show=0;
+    laNotifyUsers("la.windows.maximized_ui"); laHideMenuBar();
+}
+void laRestoreCanvasUI(){
+    laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedUi || !w->MaximizedUiPanel) return;
+    la_StopUiOperatorService(w->MaximizedUi); laRetriggerOperators(); w->MaximizedUiPanel->Show=1;
+    w->MaximizedUiPanel->Refresh |= LA_TAG_RECALC; w->MaximizedUi=0; w->MaximizedUiPanel=0; la_UpdateUiPlacement(w);
+    laNotifyUsers("la.windows.maximized_ui"); laShowMenuBar();
+}
+void laHideMenuBar(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedUi || !w->MaximizedUiPanel) return;
+    for(laPanel* p=MAIN.CurrentWindow->Panels.pFirst;p;p=p->Item.pNext){ if(p->IsMenuPanel){ p->Show=0; break; } }
+}
+void laShowMenuBar(){ for(laPanel* p=MAIN.CurrentWindow->Panels.pFirst;p;p=p->Item.pNext){ if(p->IsMenuPanel){ p->Show=1; break; } } }
+void laSplitBlockHorizon(laBlock *b, real Percentage){
+    laPanel *p;
+    b->SplitRatio = Percentage;
+    b->Vertical = 0;
+    b->B1 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B1); b->B1->Folded=b->Folded;
+    b->B2 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B2);
+    for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+        p->Block = b->B1;
+    }
+    b->B1->Panels.pFirst = b->Panels.pFirst;
+    b->B1->Panels.pLast = b->Panels.pLast;
+    b->B1->CurrentPanel = b->CurrentPanel;
+    b->B1->parent = b->B2->parent=b;
+    b->Panels.pFirst = 0;
+    b->Panels.pLast = 0;
+    b->CurrentPanel = 0;
+    la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+}
+void laSplitBlockVertical(laBlock *b, real Percentage){
+    laPanel *p;
+    b->SplitRatio = Percentage;
+    b->Vertical = 1;
+    b->B1 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B1); b->B1->Folded=b->Folded;
+    b->B2 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B2);
+    for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+        p->Block = b->B1;
+    }
+    b->B1->Panels.pFirst = b->Panels.pFirst;
+    b->B1->Panels.pLast = b->Panels.pLast;
+    b->B1->CurrentPanel = b->CurrentPanel;
+    b->B1->parent = b->B2->parent=b;
+    b->Panels.pFirst = 0;
+    b->Panels.pLast = 0;
+    b->CurrentPanel = 0;
+    la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+}
+void laCombineChildBlocks(laBlock *b){
+    laPanel *p; if(!b) return;
+    if (!b->B1->B1 && !b->B2->B1){
+        lstCombineLists(&b->Panels, &b->B1->Panels);
+        lstCombineLists(&b->Panels, &b->B2->Panels);
+        for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+            p->Block = b;
+        }
+        b->CurrentPanel = b->B1->CurrentPanel?b->B1->CurrentPanel:b->B2->CurrentPanel;
+        memFree(b->B1);
+        memFree(b->B2);
+        b->B1 = 0;
+        b->B2 = 0;
+        la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+    }elif(!b->B1->B1){
+        laBlock* b1 = b->B2->B1; laBlock* b2 = b->B2->B2;
+        b->Vertical = b->B2->Vertical;
+        for (p = b->B1->Panels.pFirst; p; p = p->Item.pNext){
+            p->Block = b1;
+        }
+        lstCombineLists(&b1->Panels, &b->B1->Panels);
+        memFree(b->B1); memFree(b->B2);
+        b->B1 = b1; b->B2 = b2;
+        b1->parent = b; b2->parent = b;
+        la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+    }elif(!b->B2->B1){
+        laBlock* b1 = b->B1->B1;laBlock* b2 = b->B1->B2;
+        b->Vertical = b->B1->Vertical;
+        for (p = b->B2->Panels.pFirst; p; p = p->Item.pNext){
+            p->Block = b1;
+        }
+        lstCombineLists(&b1->Panels, &b->B2->Panels);
+        memFree(b->B1); memFree(b->B2);
+        b->B1 = b1; b->B2 = b2;
+        b1->parent = b; b2->parent = b;
+        la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+    }
+}
+laBlock *laBlock1(laBlock *b){
+    return b->B1;
+}
+laBlock *laBlock2(laBlock *b){
+    return b->B2;
+}
+laBlock *laSwapSubBlocks(laBlock *b){
+    laBlock *tB;
+    tB = b->B2;
+    b->B2 = b->B1;
+    b->B1 = tB;
+    b->SplitRatio = 1 - b->SplitRatio;
+    la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+}
+void laDestroyBlocksRecursive(laBlock *Root){
+    laPanel *p;
+    if (Root->B1){
+        laDestroyBlocksRecursive(Root->B1);
+        laDestroyBlocksRecursive(Root->B2);
+    }else{
+        while (p = lstPopItem(&Root->Panels)){
+            laDestroySinglePanel(p);
+        }
+    }
+    memFree(Root);
+}
+laPanel* laTearOffPanel(laBlock* b, laPanel* p_if_set){
+    if(!b->CurrentPanel ) return 0;
+
+    laPanel* p = p_if_set?p_if_set:b->CurrentPanel;
+    b->CurrentPanel = p->Item.pNext?p->Item.pNext:p->Item.pPrev;
+    lstRemoveItem(&b->Panels, p);
+    if(!b->CurrentPanel && b->parent){
+        b=b->parent;
+        laCombineChildBlocks(b);
+    }
+
+    if(!p->TitleBar.UiItems.pFirst){
+        laui_DefaultPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, p->PanelTemplate->Header);
+    }
+
+    p->Mode = LA_PANEL_FLOATING_TOP;
+    p->TY-=LA_RH;
+    p->TH+=LA_RH;
+
+    p->Refresh=LA_TAG_RECALC;
+    la_RecalcBlockRecursive(b, b->X,b->Y,b->W,b->H);
+    p->BT = &_LA_THEME_FLOATING_PANEL;
+    p->Block = 0;
+    lstPushItem(&MAIN.CurrentWindow->Panels, p);
+
+    laNotifyUsers("la.windows.panels");
+
+    return b->CurrentPanel;
+}
+void laDockPanel(laWindow* from, laBlock* b, laPanel* p){
+    if(!b||!p||p->Mode!=LA_PANEL_FLOATING_TOP||b->B1||b->B2) return;
+
+    lstRemoveItem(&from->Panels, p);
+
+    la_DestroyUiList(&p->TitleBar, 1, 1, 0);
+
+    p->Mode = LA_PANEL_NORMAL;
+    p->Block=b;
+    b->CurrentPanel = p;
+    lstPushItem(&b->Panels, p);
+    p->Refresh=LA_TAG_RECALC;
+    p->BT = &_LA_THEME_PANEL;
+    la_RecalcBlockRecursive(b, b->X,b->Y,b->W,b->H);
+    tnsFlush();
+
+    laNotifyUsers("la.windows.panels");
+}
+
+void laPopPanel(laPanel *p){
+    if (p->Mode == LA_PANEL_FLOATING_PASSIVE){
+        lstRemoveItem(&p->Parent->SubPanels, p);
+        lstPushItem(&p->Parent->SubPanels, p);
+    }else if (p->Mode == LA_PANEL_FLOATING_TOP){
+        lstRemoveItem(&MAIN.CurrentWindow->Panels, p);
+        lstPushItem(&MAIN.CurrentWindow->Panels, p);
+        laNotifyUsers("la.windows.panels");
+    }
+}
+
+void la_EnsurePanelExtras(laPanel *p){
+    laUiTemplate* uit=p->PanelTemplate;
+
+    p->PropLinkContainer = memAcquire(sizeof(laPropContainer));
+    p->PropLinkFakeProp = memAcquire(sizeof(laSubProp));
+    p->PropLinkFakeProp->Base.Identifier = "LA_UI_FAKE_PROP_PLACEHOLDER";
+    p->PropLinkFakeProp->Base.PropertyType = LA_PROP_SUB;
+    p->PropLinkFakeProp->Base.SubProp = p->PropLinkContainer;
+    p->PropLinkFakeProp->Base.Offset = 0;
+    p->PropLinkFakeProp->Base.OffsetIsPointer = 1;
+
+    p->PropLinkPP.EndInstance = p;
+    p->PropLinkPP.LastPs = &p->PropLinkFakePS;
+    p->PropLinkPP.LastPs->Type = L'.';
+    p->PropLinkFakePS.p = p->PropLinkFakeProp;
+}
+laPanel *la_NewPanel(laUiTemplate* uit, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB){
+    laPanel *p = memAcquireHyper(sizeof(laPanel));
+    int CW = MAIN.CurrentWindow->CW;
+    int CH = MAIN.CurrentWindow->CH;
+    p->PanelTemplate = uit;
+
+    if (!MaxW) MaxW = 10000;
+    if (!MaxH) MaxH = 10000;
+
+    if (W > MaxW) W = MaxW;
+    if (H > MaxH) H = MaxH;
+
+    if (W < MinW) W = MinW;
+    if (H < MinH) H = MinH;
+
+    if(uit) { strSafeSet(&p->Title, uit->Title->Ptr); }
+    p->X = p->TX = (X < 0 ? 0 : X);
+    p->Y = p->TY = (Y < 0 ? 0 : Y);
+    p->W = p->TW = (W < 0 ? CW + W - p->X : W);
+    p->H = p->TH = (H < 0 ? CH + H - p->Y : H);
+
+    p->MaxW = MaxW;
+    p->MaxH = MaxH;
+    p->MinW = MinW;
+    p->MinH = MinH;
+
+    p->SL = SnapL;
+    p->ST = SnapT;
+    p->SR = SnapR;
+    p->SB = SnapB;
+
+    if (p->SR) p->X = CW - p->W - p->SR;
+    if (p->SB) p->Y = CH - p->H - p->SB;
+
+    la_EnsurePanelSnapping(p, CW, CH);
+
+    p->Show = 1;
+    p->PP.EndInstance = p;
+    p->PP.LastPs = &p->FakePS;
+    p->PP.LastPs->p = _LA_PROP_PANEL;
+    p->PP.LastPs->UseInstance = p;
+    p->PP.LastPs->Type = L'.';
+
+    la_EnsurePanelExtras(p);
+
+    p->Refresh = LA_TAG_RECALC;
+    p->FrameDistinguish = 100; //greater than 1 is ok
+
+    if(uit&&uit->PropFunc){ uit->PropFunc(p); }
+    if(uit){uit->Define(&p->UI, &p->PP, &p->PropLinkPP, 0, 0);}
+
+    return p;
+}
+laPanel *laCreatePanelT(laBlock *b, laUiTemplate* uit){
+    if(!uit) return 0;
+
+    laPanel *p = memAcquireHyper(sizeof(laPanel));
+
+    strSafeSet(&p->Title, uit->Title->Ptr);
+    p->PanelTemplate = uit;
+
+    p->Show = 1;
+    p->PP.EndInstance = p;
+    p->PP.LastPs = &p->FakePS;
+    p->PP.LastPs->p = _LA_PROP_PANEL;
+    p->PP.LastPs->UseInstance = p;
+    p->PP.LastPs->Type = L'.';
+
+    la_EnsurePanelExtras(p);
+
+    p->Refresh = LA_TAG_RECALC;
+    p->FrameDistinguish = 100; //greater than 1 is ok
+
+    p->TitleWidth = tnsStringGetWidth(p->Title->Ptr, 0, 0);
+
+    while (b->B1){
+        b = b->B1;
+    }
+    lstPushItem(&b->Panels, p);
+    p->Block = b;
+    b->CurrentPanel = p;
+
+    if(uit->PropFunc){ uit->PropFunc(p); }
+    uit->Define(&p->UI, &p->PP, &p->PropLinkPP, 0, 0);
+
+    laNotifyUsers("la.windows.panels");
+
+    return p;
+}
+laPanel *laCreatePanel(laBlock *b, char *template_id){
+    laUiTemplate* uit=laFindUiTemplate(template_id);
+    return laCreatePanelT(b, uit);
+}
+laPanel *laCreateTopPanel(laWindow *w, char *template_id, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB){
+    laUiTemplate* uit=0;
+    if(template_id) uit=laFindUiTemplate(template_id);
+    laPanel *p = la_NewPanel(uit, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB);
+    p->Mode = LA_PANEL_FLOATING_TOP;
+
+    if(uit){
+        laui_DefaultPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, p->PanelTemplate->Header);
+    }
+
+    if (w) lstPushItem(&w->Panels, p);
+
+    return p;
+}
+void laShowPanel(laPanel *p){
+    p->Show = 1;
+    laNotifyUsers("la.windows.panels_hidden");
+}
+void laShowPanelWithDropDownEffect(laPanel *p){
+    laShowPanel(p);
+    p->AnimationMode = LA_PANEL_ANIMATION_DROP_DOWN;
+    p->AnimationRatio = 0;
+}
+void laShowPanelWithExpandEffect(laPanel *p){
+    laShowPanel(p);
+    p->AnimationMode = LA_PANEL_ANIMATION_EXPAND;
+    p->AnimationRatio = 0;
+}
+void laHidePanel(laPanel *p){
+    if (!p->Mode) return;
+    p->Show = 0;
+    laNotifyUsers("la.windows.panels_hidden");
+}
+void laHidePanelWithDissoveEffect(laPanel *p){
+    if (!p->Mode) return;
+    laHidePanel(p);
+    p->AnimationMode = LA_PANEL_ANIMATION_DISSOVE;
+    p->AnimationRatio = 1;
+}
+void laHidePanelWithCollapseEffect(laPanel *p){
+    if (!p->Mode) return;
+    laHidePanel(p);
+    p->AnimationMode = LA_PANEL_ANIMATION_COLLAPSE;
+    p->AnimationRatio = 1;
+}
+void laHidePanelWithMinimizeEffect(laPanel *p){
+    if (!p->Mode) return;
+    laHidePanel(p);
+    p->AnimationMode = LA_PANEL_ANIMATION_MINIMIZE;
+    p->AnimationRatio = 1;
+}
+void laActivatePanel(char* TemplateID, int x, int y){
+    laUiTemplate* uit = laFindUiTemplate(TemplateID);
+    laPanel *p = la_FindFreePanelByTemplate(MAIN.CurrentWindow, uit);
+    if (!p){ p=laCreateTopPanel(MAIN.CurrentWindow, TemplateID, x, y, 400,400, 0, 0, 0, 0, 0, 0, 0, 0); }
+    laShowPanelWithExpandEffect(p); laPopPanel(p);
+}
+void laPanPanel(laPanel *p, int DeltaX, int DeltaY){
+    p->UI.PanX += DeltaX;
+    p->UI.PanY += DeltaY;
+}
+int laPanUiListFree(laUiList *uil, int X, int Y){
+    uil->PanX+=X; uil->PanY+=Y;
+}
+int laPanUiList(laUiList *uil, int X, int Y, int L, int R, int U, int B){
+    if(uil->ScrollerShownH && !uil->ScrollerShownV){
+        if(Y){X+=Y;Y=0;}
+    }
+    if (Y > 0){
+        if (uil->B - uil->PanY <= B) return 0;
+        else{
+            uil->PanY += Y;
+            if (uil->B - uil->PanY <= B){
+                uil->PanY = uil->B - B;
+                return 1;
+            }
+        }
+    }
+    if (Y < 0){
+        if (uil->U - uil->PanY >= U) return 0;
+        else{
+            uil->PanY += Y;
+            if (uil->U - uil->PanY >= U){
+                uil->PanY = uil->U - U;
+                return 1;
+            }
+        }
+    }
+
+    if(uil->AllowScale){
+        laPanUiListFree(uil, X, 0);
+    }else{
+        if (X > 0){
+            if (uil->R - uil->PanX <= R) return 0;
+            else{
+                uil->PanX += X;
+                if (uil->R - uil->PanX <= R){
+                    uil->PanX = uil->R - R;
+                    return 1;
+                }
+            }
+        }
+        if (X < 0){
+            if (uil->L - uil->PanX >= L) return 0;
+            else{
+                uil->PanX += X;
+                if (uil->L - uil->PanX >= L){
+                    uil->PanX = uil->L - L;
+                    return 1;
+                }
+            }
+        }
+    }
+    return 1;
+}
+int laScaleUiList(laUiList *uil, real factor, int L, int R, int U, int B){
+    int ret=1;
+    if(!uil->AllowScale){ return 0; }
+    real NewScale=uil->Scale*factor;
+
+    if(NewScale<0.2){NewScale=0.2; ret=0;}
+    if(NewScale>5)  {NewScale=5; ret=0;}
+    if(NewScale>1-1e-4 && NewScale<1+1e-4){NewScale=1;}
+
+    factor=NewScale/uil->Scale;
+    uil->Scale=NewScale;
+
+    real mx=(L+R)/2,my=(U+B)/2;
+    real dx= (mx+uil->PanX)*factor;
+    real dy= (my+uil->PanY)*factor;
+    uil->PanX=dx-mx;
+    uil->PanY=dy-my;
+
+    MAIN.CurrentPanel->FrameDistinguish=100;
+
+    return ret;
+}
+int laPanUiListAuto(laUiList *uil, int X, int Y, int L, int R, int U, int B){
+    if(uil->AllowScale) return 0;
+    return laPanUiList(uil,X,Y,L,R,U,B);
+}
+
+laPanel *laDesignPropPanel(char *Title, int X, int Y, int W, int H,
+                           laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps){
+    laPanel *p = la_NewPanel(0, X, Y, W, H, 0, H, 0, 0, 0, 0, 0, 0);
+    strSafeSet(&p->Title, Title);
+
+    if (Define){
+        Define(laPrepareUi(p), This, OperatorProps, NULL, 0);
+    }
+
+    //laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, OperatorProps, 0, 0);
+
+    p->BT= &_LA_THEME_FLOATING_PANEL;
+    p->Mode = LA_PANEL_FLOATING_PASSIVE;
+    p->BoundUi = 1;
+
+    return p;
+}
+laPanel *laDesignOperatorPanel(char *Title, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB,
+                               laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps){
+    laPanel *p = la_NewPanel(0, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB);
+    strSafeSet(&p->Title, Title);
+
+    if (Define){
+        Define(laPrepareUi(p), This, OperatorProps, NULL, 0);
+    }
+
+    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, OperatorProps, 0, 0);
+
+    p->BT= &_LA_THEME_FLOATING_PANEL;
+    p->Mode = LA_PANEL_FLOATING_TOP;
+    p->BoundUi = 1;
+
+    return p;
+}
+
+void laDeferredDestroyPanel(laPanel *p){
+    laPanel *ip;
+    tnsDelete2DOffscreen(p->OffScr);
+    p->OffScr = 0;
+
+    strSafeDestroy(&p->Title);
+
+    if (!p->AnimationMode){
+        if (p->Parent) lstRemoveItem(&p->Parent->SubPanels, p);
+        else if (p->Mode == LA_PANEL_FLOATING_TOP){
+            lstRemoveItem(&MAIN.CurrentWindow->Panels, p);
+        }else if (p->Mode == LA_PANEL_NO_PARENT_MENU){
+            lstRemoveItem(&MAIN.CurrentWindow->Panels, p);
+        }else if (p->Block){
+            lstRemoveItem(&p->Block->Panels, p);
+            if (p->Block->CurrentPanel == p) p->Block->CurrentPanel = p->Block->Panels.pFirst;
+        }
+        laNotifyUsers("la.windows.panels");
+    }
+
+    for (ip = p->SubPanels.pFirst; ip; ip = ip->Item.pNext){
+        //lstRemoveItem(&p->SubPanels, ip);
+        laDestroySinglePanel(ip);
+        laNotifyUsers("la.windows.panels");
+    }
+
+    memFree(p->PropLinkContainer); memFree(p->PropLinkFakeProp);
+
+    memFree(p);
+}
+void laDestroySinglePanel(laPanel *p){
+    la_SetPropMathcerContext(p);
+
+    if (p->PropLinkPP.LastPs->p->SubProp->Props.pFirst){
+        for(laProp* prop=p->PropLinkPP.LastPs->p->SubProp->Props.pFirst;prop;prop=prop->Item.pNext){
+            la_StopUsingPropPack(&prop->DetachedPP);
+            //laStopUsingDataBlock(prop->DetachedPP.LastPs->UseInstance, prop->DetachedPP.LastPs->p,MAIN.PropMatcherContextP);
+        }
+    }
+
+    if(p==MAIN.CurrentWindow->MaximizedUiPanel){ laRestoreCanvasUI(); }
+
+    la_DestroyUiList(&p->UI, 1, 1, 0);
+    la_DestroyUiList(&p->TitleBar, 1, 1, 0);
+    la_DestroyUiList(p->MenuRefer, 0, 1, 1);
+
+    if (p->Mode){
+        p->AnimationMode = LA_PANEL_ANIMATION_DISSOVE;
+        p->AnimationRatio = p->CloseWhenMovedOut?0.0:1.0;
+    }
+
+    if (p->ParentOperator && la_UiOperatorExists(p)) ((laOperator *)p->ParentOperator)->OperatorPanel = 0;
+
+    if (la_UiStillInService(p)){
+        la_StopUiOperatorService(p);
+    }
+
+    if (!p->AnimationMode){
+        laDeferredDestroyPanel(p);
+    }else{
+        p->LaterDestroy = 1;
+    }
+}
+
+int laEnclosePanelContent(laPanel *p, laUiList *uil){
+    laBoxedTheme *bt = _LA_THEME_FLOATING_PANEL;
+    int MinW,MinWt=0;
+    int TitleReserve=p->Mode==LA_PANEL_FLOATING_TOP?LA_RH:0;
+    int CW = MAIN.CurrentWindow->CW;
+    if(p->SL && p->SR){return 0;}
+    la_SetPropMathcerContext(p);
+
+    la_UpdateUiListRecursive(&p->TitleBar, bt->TM, bt->LM, p->TW - bt->LM-bt->RM, p->TH, 0, p);
+    la_UpdateUiListRecursive(uil, bt->TM+p->TitleBar.B, 0, 1000, 0, 0, p);
+    MinWt = la_TestUiListMinumWidth(&p->TitleBar);
+    MinW = la_TestUiListMinumWidth(uil);
+    if (MinW<MinWt){MinW=MinWt;}
+    int ScrollerW=(uil->ScrollerShownV?(LA_SCROLL_W+bt->RM):0);
+    if (MinW > 20){
+        p->TW = MinW + bt->LM + bt->RM+ScrollerW;
+    }
+    la_PanelValidateWidth(p,uil);
+    laEnsurePanelInBound(p,uil);
+    if(p->TW>CW){ p->TW=CW; }
+    la_UpdateUiListRecursive(&p->TitleBar, bt->TM, bt->LM, p->TW - bt->LM-bt->RM, p->TH, 0, p);
+    la_UpdateUiListRecursive(uil, bt->TM+p->TitleBar.B, bt->LM, p->TW - bt->RM - ScrollerW, 0, 0, p);
+    p->Refresh=LA_TAG_REDRAW;
+    return 1;
+}
+laPanel *laEnableIdlePanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laPropPack *This,
+                               int L, int R, int B, int MaxGH, int MaxW, laEvent *e){
+    laOperator *ai = a;
+    laPanel *p;
+    int GX, GY, GW, t = 0;
+    int b;
+    laUiDefineFunc def = ReplaceUiDefine;
+    int MinW;
+
+    if (!def){ def=laui_DefaultPropDetails; }
+
+    GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L);
+
+    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, This, OperatorProps);
+    laEnclosePanelContent(p, &p->UI);
+    laSetOperatorLocalizer(p);
+    p->CloseWhenMovedOut=1;
+    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);
+
+    //laShowPanelWithDropDownEffect(p);
+
+    if(!Attachment){ Attachment=MAIN.CurrentWindow->MaximizedUiPanel; }
+    if(Attachment){ p->Parent = Attachment; lstAppendItem(&Attachment->SubPanels, p); }
+
+    return p;
+}
+laPanel *laEnablePropertyPanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laPropPack *This,
+                               int L, int R, int B, int MaxGH, int MaxW, laEvent *e){
+    laOperator *ai = a;
+    laPanel *p;
+    int GX, GY, GW, t = 0;
+    int b;
+    laUiDefineFunc def = ReplaceUiDefine;
+    int MinW;
+
+    if (!def){
+        if (This && This->LastPs->p->UiDefine) def = This->LastPs->p->UiDefine;
+        if (!def && This->LastPs->p->SubProp && This->LastPs->p->SubProp->UiDefine) def=This->LastPs->p->SubProp->UiDefine;
+        else def = laui_DefaultPropUiDefine;
+    }
+
+    //laLocalToWindow(0,Attachment, &L, &t);
+    //laLocalToWindow(0,Attachment, &R, &B);
+
+    GX = L;
+    GY = B;
+    GW = (R - L) > MaxW ? MaxW : (R - L);
+
+    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, This, OperatorProps);
+    laEnclosePanelContent(p, &p->UI);
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);
+
+    laShowPanelWithDropDownEffect(p);
+
+    if(!Attachment){ Attachment=MAIN.CurrentWindow->MaximizedUiPanel; }
+    if(Attachment){
+        p->Parent = Attachment;
+        lstAppendItem(&Attachment->SubPanels, p);
+    }
+
+    return p;
+}
+laPanel *laEnableEmptyPropertyPanel(laPanel *Attachment, laOperator *a, int L, int R, int U, int MaxGH, laEvent *e){
+    laPanel *p;
+    int t = 0;
+    int b;
+
+    //laLocalToWindow(0, Attachment, &L, &t);
+    //laLocalToWindow(0, Attachment, &R, &U);
+
+    p = laDesignPropPanel("TMP", L, U, R - L, MaxGH, 0, 0, 0);
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);
+
+    laShowPanelWithDropDownEffect(p);
+
+    p->Parent = Attachment;
+    lstPushItem(&Attachment->SubPanels, p);
+
+    return p;
+}
+laPanel *laEnableMenuPanel(laPanel *Attachment, laOperator *a, laUiList *MenuRefer, laPropPack *This,
+                           int L, int R, int B, int MaxGH, int MaxW, laEvent *e){
+    laOperator *ai = a;
+    laPanel *p;
+    laBoxedTheme *bt = _LA_THEME_FLOATING_PANEL;
+    int GX, GY, GW, t = 0;
+    int b;
+    int MinW;
+
+    //laLocalToWindow(0,Attachment, &L, &t);
+    //laLocalToWindow(0,Attachment, &R, &B);
+
+    GX = L;
+    GY = B;
+    GW = (R - L) > MaxW ? MaxW : (R - L);
+
+    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, 0, 0, 0);
+    p->MenuRefer = MenuRefer;
+
+    laEnclosePanelContent(p, MenuRefer);
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);
+
+    laShowPanelWithDropDownEffect(p);
+
+    p->Parent = Attachment;
+    lstPushItem(&Attachment->SubPanels, p);
+
+    return p;
+}
+laPanel *laDefineAndEnableMenuPanel(laPanel *Attachment, laOperator *a, laPropPack *This,
+                                    int L, int B, int MaxGH, int MaxW, laEvent *e){
+    laOperator *ai = a;
+    laPanel *p;
+    int GX, GY, GW, t = 0;
+    int b;
+
+    GX = L;
+    GY = B;
+    GW = MaxW;
+
+    p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, 0, 0, 0);
+    p->MenuRefer = &p->UI;
+    
+    p->Mode = LA_PANEL_NO_PARENT_MENU;
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1);
+
+    laShowPanelWithDropDownEffect(p);
+
+    if (Attachment){
+        p->Parent = Attachment;
+        lstPushItem(&Attachment->SubPanels, p);
+    }else{
+        lstPushItem(&MAIN.CurrentWindow->Panels, p);
+    }
+
+    return p;
+}
+laPanel *laEnableOperatorPanel(laOperator *For, laPropPack *This, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB, laEvent *e){
+    laOperator *ai = For;
+    laPanel *p;
+    int b;
+    laUiDefineFunc def = 0;
+
+    if (ai->Type->UiDefine) def = ai->Type->UiDefine;
+    else def = laui_DefaultPropUiDefine;
+    
+    For->PP.EndInstance = For->CustomData;
+
+    p = laDesignOperatorPanel(ai->Type->Name, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB, def, This, &For->PP);
+    laEnclosePanelContent(p, &p->UI);
+    MAIN.ToPanel = p;
+
+    laShowPanelWithExpandEffect(p);
+
+    lstPushItem(&MAIN.CurrentWindow->Panels, p);
+    ai->OperatorPanel = p;
+    p->ParentOperator = For;
+
+    laInvokeUi(For, "LA_modal_panel_operator", 0, p, 0, 1);
+
+    return p;
+}
+laPanel *laEnableYesNoPanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e){
+    laPanel *p;
+    int b;
+    laUiList *uil;
+    laColumn *col, *cor, *corl, *corr;
+
+    p = la_NewPanel(0, X, Y, W, 0, 1000, 500, 50, 0, 0, 0, 0, 0);
+    strSafeSet(&p->Title, Title);
+    p->BoundUi = 1;
+    p->Mode = LA_PANEL_FLOATING_TOP;
+    p->BT = &_LA_THEME_FLOATING_PANEL;
+    MAIN.ToPanel = p;
+
+    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);
+
+    uil = laPrepareUi(p);
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.5);
+    cor = laRightColumn(col, 600);
+
+    laShowLabel(uil, col, Message, 0, 0);
+    laShowItem(uil, cor, 0, "LA_confirm")->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_TEXT_ALIGN_CENTER;
+
+    laEnclosePanelContent(p,uil);
+    laShowPanelWithExpandEffect(p);
+
+    lstPushItem(&MAIN.CurrentWindow->Panels, p);
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1);
+
+    return p;
+}
+laPanel *laEnableMessagePanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e){
+    laPanel *p;
+    int b;
+    laUiList *uil;
+    laColumn *col, *cor, *corl, *corr;
+
+    p = la_NewPanel(0, X, Y, W, 0, 1000, 90, 100, 0, 0, 0, 0, 0);
+    strSafeSet(&p->Title, Title);
+    p->BoundUi = 1;
+    p->Mode = LA_PANEL_FLOATING_TOP;
+    p->BT = &_LA_THEME_FLOATING_PANEL;
+    MAIN.ToPanel = p;
+
+    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);
+
+    uil = laPrepareUi(p);
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.35);
+    cor = laRightColumn(col, 200);
+
+    laShowLabel(uil, col, Message, 0, 0);
+
+    laShowItemFull(uil, cor, 0, "LA_confirm",0,"text=Okay;",0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT;
+
+    laEnclosePanelContent(p,uil);
+    laShowPanelWithExpandEffect(p);
+
+    lstPushItem(&MAIN.CurrentWindow->Panels, p);
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1);
+
+    return p;
+}
+laPanel *laEnableMultiMessagePanel(laOperator *a, laPanel *Attachment, char *Title, laPanelMessageList *pml, int X, int Y, int W, laEvent *e){
+    laPanel *p;
+    int b;
+    laUiList *uil;
+    laColumn *col, *cor, *corl, *corr;
+    laPanelMessage *pm;
+
+    p = la_NewPanel(0, X, Y, W, 0, 1000, 1000, 100, 0, 0, 0, 0, 0);
+    strSafeSet(&p->Title, Title);
+    p->BoundUi = 1;
+    p->Mode = LA_PANEL_FLOATING_TOP;
+    p->BT = &_LA_THEME_FLOATING_PANEL;
+    MAIN.ToPanel = p;
+
+    laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);
+
+    uil = laPrepareUi(p);
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.35);
+    cor = laRightColumn(col, 200);
+
+    while (pm = lstPopItem(pml)){
+        laShowLabel(uil, col, pm->Message->Ptr, 0, 0);
+        strSafeDestroy(&pm->Message);
+        FreeMem(pm);
+    }
+
+    laShowItemFull(uil, cor, 0, "LA_confirm",0,"text=Okay;",0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT;
+
+    laShowPanelWithExpandEffect(p);
+
+    lstPushItem(&MAIN.CurrentWindow->Panels, p);
+    laSetOperatorLocalizer(p);
+    laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1);
+
+    return p;
+}
+
+void laAddPanelMessage(laPanelMessageList *pml, char *Message){
+    if (!Message || !Message[0]) return;
+    laPanelMessage *pm = CreateNew(laPanelMessage);
+    strSafeSet(&pm->Message, Message);
+    lstAppendItem(&pml->Msg, pm);
+}
+
+void laRedrawAllWindows(){
+    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext) la_UpdateUiPlacement(w);
+}
+void laRedrawCurrentWindow(){
+    if (MAIN.CurrentWindow) la_UpdateUiPlacement(MAIN.CurrentWindow);
+}
+void laRedrawCurrentPanel(){
+    if (MAIN.CurrentPanel) MAIN.CurrentPanel->Refresh |= LA_TAG_REDRAW;
+    elif (MAIN.CurrentWindow->MaximizedUiPanel) MAIN.CurrentWindow->MaximizedUiPanel->Refresh |= LA_TAG_REDRAW;
+}
+void laRecalcCurrentPanel(){
+    if (MAIN.CurrentPanel) MAIN.CurrentPanel->Refresh |= LA_TAG_RECALC;
+    elif (MAIN.CurrentWindow->MaximizedUiPanel) MAIN.CurrentWindow->MaximizedUiPanel->Refresh |= LA_TAG_RECALC;
+} 
+void laRecalcPanelImmediate(laPanel* p){
+    p->FrameDistinguish++;
+    laBoxedTheme* bt = (*p->BT);
+    int scrollw=p->UI.ScrollerShownV?bt->RM*2+LA_SCROLL_W:0;
+    la_PanelRefreshDetachedProp(p);
+    int enclosed=0;
+    if(p->BoundUi || p->MenuRefer){
+        if(p->MenuRefer) enclosed=laEnclosePanelContent(p, p->MenuRefer);
+        else enclosed=laEnclosePanelContent(p, &p->UI);
+    }
+    if(!enclosed){
+        la_PanelValidateWidth(p,&p->UI);
+        //laEnsurePanelInBound(p,&p->UI);
+        la_UpdateUiListRecursive(&p->TitleBar, bt->TM, bt->LM, p->TW-bt->RM, p->TH-bt->TM-bt->BM, 0, p);
+        la_UpdateUiListRecursive(&p->UI, bt->TM+p->TitleBar.TB, bt->LM, p->TW-bt->RM-scrollw, p->TH-bt->TM-bt->BM, 0, p);
+    }
+    laWindow* w=MAIN.CurrentWindow;
+    if(w->MaximizedUiPanel==p&&w->MaximizedUi){ int CW = w->CW; int CH = w->CH;
+        laUiItem* ui=w->MaximizedUi; ui->TU=ui->U=0; ui->TB=ui->B=CH; ui->TL=ui->L=0; ui->TR=ui->R=CW;
+        if(!ui->Page) return; laBoxedTheme* bt=(*ui->Type->Theme);
+        la_UpdateUiListRecursive(ui->Page, ui->TU+bt->TM, ui->TL+bt->LM, ui->TR-bt->RM, ui->TB, 0, w->MaximizedUiPanel);
+    }
+}
+void laRecalcCurrentPanelImmediate(){
+    laRecalcPanelImmediate(MAIN.CurrentPanel);
+}
+int laNonFixedPanelExists(laPanel *p){
+    laPanel *ip;
+
+    if (!p) return 0;
+
+    //for (ip = MAIN.CurrentWindow->CurrentLayout->Panels.pLast; ip; ip = ip->Item.pPrev) {
+    //	if (ip == p) return 1;
+    //}
+
+    for (ip = MAIN.CurrentWindow->Panels.pLast; ip; ip = ip->Item.pPrev){
+        if (ip == p) return 1;
+    }
+
+    return 0;
+}
+int laIsInPanel(laPanel *p, int PanelX, int PanelY){
+    if (PanelX < 0 || PanelY < 0 || PanelY > p->H || PanelX > p->W) return 0;
+    return 1;
+}
+int laIsCloseToPanel(laPanel *p, int PanelX, int PanelY){
+    int tt=MAIN.TooltipCloseDistance;
+    if (PanelX < -tt || PanelY < -tt || PanelY > p->H+tt || PanelX > p->W+tt) return 0;
+    return 1;
+}
+int laPanelOverlappingEachOther(laPanel *p1, laPanel *p2){
+    if (p1->X > p2->X + p2->W || p1->X + p1->W < p2->X ||
+        p1->Y > p2->Y + p2->H || p1->Y + p1->H < p2->Y)
+        return 0;
+    return 1;
+}
+void laUnlinkSharedPanel(laPanel *p){
+    laWindow *w;
+    laPanel *ip;
+
+    for (w = MAIN.Windows.pFirst; w; w = w->Item.pNext){
+        for (ip = w->Panels.pFirst; ip; ip = ip->Item.pNext){
+            if (ip == p){
+                lstRemoveItem(&w->Panels, ip);
+                return;
+            }
+        }
+    }
+}
+int laIsPanelCovered(laPanel *p){
+    //laLayout* l = MAIN.CurrentWindow->CurrentLayout;
+    laPanel *ip;
+    laPanel *resp;
+    int in1 = 0, in2 = 0, in3 = 0;
+    laPanel *d1 = 0, *d2 = 0, *d3 = 0;
+
+    //for (ip = MAIN.CurrentWindow->CurrentLayout->Panels.pLast; ip; ip = ip->Item.pPrev) {
+    //	if (ip == p) { in1 = 1; d1 = 0; continue; }
+    //	if (ip->Show && laPanelOverlappingEachOther(ip, p)) d1 = ip;
+    //}
+
+    for (ip = MAIN.CurrentWindow->Panels.pLast; ip; ip = ip->Item.pPrev){
+        if (ip == p){
+            in3 = 1;
+            d3 = 0;
+            continue;
+        }
+        if (ip->Show && laPanelOverlappingEachOther(ip, p)) d3 = ip;
+    }
+
+    if (!in2 && !in3) in1 = 1;
+
+    if (in1){
+        if (d1 || d2 || d3) return 1;
+    }else{
+        if (in2){
+            if (d2 || d3) return 1;
+        }else if (in3)
+            if (d3) return 1;
+    }
+
+    return 0;
+}
+int laIsTopPanel(laPanel *p){
+    //if (!p->Item.pPrev) return 1;
+    //else {
+    if (!laIsPanelCovered(p)){
+        //laPopPanel(p);
+        return 1;
+    }
+    return 0;
+    //}
+    return 0;
+}
+void laWindowToLocal(laOperator *a, laPanel *p, int *x, int *y){
+    if(!p) return;
+    int ix = *x, iy = *y;
+    laListItemPointer *lip;
+    laOperator *ai = a;
+    (*x) = ix - p->X;
+    (*y) = iy - p->Y;
+    if (a){
+        for (lip = ai->LocalUiLists.pFirst; lip; lip = lip->pNext){
+            laUiList *uil = lip->p;
+            (*x) += uil->PanX;
+            (*y) += uil->PanY;
+        }
+    }
+}
+void laPanelToLocal(laOperator *a, int *x, int *y){
+    int ix = *x, iy = *y;
+    laListItemPointer *lip;
+    if (a){
+        for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){
+            laUiList *uil = lip->p;
+            (*x) += uil->PanX;
+            (*y) += uil->PanY;
+        }
+    }
+}
+void laLocalToWindow(laOperator *a, laPanel *p, int *x, int *y){
+    if(!p) return;
+    int ix = *x, iy = *y;
+    laListItemPointer *lip;
+    (*x) = ix + p->X;
+    (*y) = iy + p->Y;
+    if (a){
+        for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){
+            laUiList *uil = lip->p;
+            (*x) -= uil->PanX;
+            (*y) -= uil->PanY;
+        }
+    }
+}
+void laPanelToWindow(laPanel *p, int *x, int *y){
+    int ix = *x, iy = *y;
+    laListItemPointer *lip;
+    (*x) = ix + p->X;
+    (*y) = iy + p->Y;
+}
+void laLocalToPanel(laOperator *a, int *x, int *y){
+    int ix = *x, iy = *y;
+    laListItemPointer *lip;
+    if (a){
+        for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){
+            laUiList *uil = lip->p;
+            (*x) -= uil->PanX;
+            (*y) -= uil->PanY;
+        }
+    }
+}
+void laSetNextMenuPos(int X, int Y, int W, int H){
+    MAIN.NextX = X;
+    MAIN.NextY = Y;
+    MAIN.NextW = W;
+    MAIN.NextH = H;
+}
+int laIsInBlock(laBlock *b, int X, int Y){
+    if (X >= b->X && X <= b->X + b->W && Y >= b->Y && Y <= b->Y + b->H) return 1;
+    return 0;
+}
+int laIsInBlockHeader(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + b->W && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; }
+int laIsInBlockBotton1(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + LA_RH && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; }
+int laIsInBlockBotton2(laBlock *b, int X, int Y){ if (X >= b->X+LA_RH && X <= b->X+LA_2RH && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; }
+laBlock *laDetectBlockRecursive(laBlock *b, int X, int Y){
+    laPanel *p;
+    laBlock *sb = 0;
+    if (!laIsInBlock(b, X, Y)) return 0;
+    if (!b->B1 && !b->B2) return b;
+    if (sb = laDetectBlockRecursive(b->B1, X, Y)) return sb;
+    return laDetectBlockRecursive(b->B2, X, Y);
+}
+laPanel *laDetectPanel(int X, int Y){
+    laPanel *p; laBlock *b;
+
+    for (p = MAIN.CurrentWindow->Panels.pFirst; p; p = p->Item.pNext){
+        int x = X, y = Y;
+        laWindowToLocal(0, p, &x, &y);
+        if (p->Show && laIsInPanel(p, x, y)){
+            return p;
+        }
+    }
+
+    if(MAIN.CurrentWindow->MaximizedUiPanel){return 0;}
+
+    laBlock* RootBlock=MAIN.CurrentWindow->MaximizedBlock?MAIN.CurrentWindow->MaximizedBlock:MAIN.CurrentWindow->CurrentLayout->FirstBlock;
+    if (b = laDetectBlockRecursive(RootBlock, X, Y)) return b->CurrentPanel;
+
+    return 0;
+}
+
+laUiList *laPrepareUi(laPanel *p){
+    return &p->UI;
+}
+laColumn *laFirstColumn(laUiList *uil){
+    if (uil->Columns.pFirst) return uil->Columns.pFirst;
+    else{
+        laColumn *c = memAcquireSimple(sizeof(laColumn));
+        c->SP = 1;
+        c->PreWidth = 1;
+        lstAppendItem(&uil->Columns, c);
+        c->Top = c;
+        return uil->Columns.pFirst;
+    }
+}
+laColumn *laSplitColumn(laUiList *uil, laColumn *c, real Percent){
+    laColumn *lc, *rc;
+
+    if (c->LS || c->RS) return c;
+
+    lc = memAcquireSimple(sizeof(laColumn));
+    rc = memAcquireSimple(sizeof(laColumn));
+
+    c->LS = lc;
+    c->RS = rc;
+
+    c->LS->SP = Percent;
+    c->RS->SP = Percent;
+
+    c->LS->Top = c->Top;
+    c->RS->Top = c->Top;
+
+    if (uil){
+        lstAppendItem(&uil->Columns, lc);
+        lstAppendItem(&uil->Columns, rc);
+    }
+
+    if (c->LS && c->RS->MaxW == 0){
+        c->LS->PreWidth = c->PreWidth * c->LS->SP;
+        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);
+    }else if (c->RS && c->LS->MaxW == 0){
+        c->LS->PreWidth = c->PreWidth * c->LS->SP;
+        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);
+    }
+    return c;
+}
+laColumn *laLeftColumn(laColumn *c, int MaxWidth){
+    if (c->LS && MaxWidth) c->LS->MaxW = MaxWidth;
+    return c->LS;
+}
+laColumn *laRightColumn(laColumn *c, int MaxWidth){
+    if (c->LS && c->LS->MaxW && MaxWidth) return c->RS;
+    if (MaxWidth) c->RS->MaxW = MaxWidth;
+    return c->RS;
+}
+
+void la_DestroyColumnRecursive(laListHandle *List, laColumn *c){
+    lstRemoveItem(List, c);
+    if (c->LS) la_DestroyColumnRecursive(List, c->LS);
+    if (c->RS) la_DestroyColumnRecursive(List, c->RS);
+    memFree(c);
+}
+
+int laCheckAndMergeSubColumnsUiList(laUiList *TopUil, laColumn *c, int DoMerge){
+    laUiList *uil = TopUil;
+    laUiList *sub;
+    laUiItem *ui;
+    laColumn *cc, *NextCC = 0;
+    int Occupied = 0;
+    int Removed = 0;
+
+    if (!c->LS) return 0;
+    else{
+        laCheckAndMergeSubColumnsUiList(TopUil, c->LS, DoMerge);
+        laCheckAndMergeSubColumnsUiList(TopUil, c->RS, DoMerge);
+    }
+
+    for (ui = TopUil->UiItems.pFirst; ui; ui = ui->Item.pNext){
+        if (ui->C == c->LS || ui->C == c->RS){
+            if (DoMerge){
+                ui->C = c;
+                Occupied = 1;
+            }else
+                return 1;
+        }
+        if (ui->Subs.pFirst){
+            for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                laCheckAndMergeSubColumnsUiList(sub, c, DoMerge);
+            }
+        }
+    }
+
+    if (!Removed){
+        for (cc = uil->Columns.pFirst; cc; cc = cc->Item.pNext){
+            if (cc == c){
+                if (c->LS) la_DestroyColumnRecursive(&uil->Columns, c->LS);
+                if (c->RS) la_DestroyColumnRecursive(&uil->Columns, c->RS);
+                c->LS = 0;
+                c->RS = 0;
+                Removed = 1;
+                break;
+            }
+        }
+    }
+
+    return Occupied;
+}
+
+laPropContainer* laUiHasExtraProps(laUiType *ut, int size, int hyper){
+    ut->ExtraProps = laAddPropertyContainer(ut->Identifier, 0,0,L'◳',0,size,0,0,hyper);
+    ut->FakeProp = memAcquire(sizeof(laSubProp));
+    ut->FakeProp->Base.SubProp = ut->ExtraProps;
+    ut->FakeProp->Base.Identifier = ut->Identifier;
+    ut->FakeProp->Base.PropertyType = LA_PROP_SUB;
+    ut->FakeProp->Base.Offset = offsetof(laUiItem, Extra);
+    ut->FakeProp->Base.OffsetIsPointer = 1;
+    //ut->FakeProp->Base.Container = ut->ExtraProps;
+    return ut->ExtraProps;
+}
+laPropContainer* laCanvasHasExtraProps(laCanvasTemplate *ct, int size, int hyper){
+    ct->ExtraProps = laAddPropertyContainer(ct->Identifier->Ptr, 0,0,L'◳',0,size,0,0,hyper);
+    ct->FakeProp = memAcquire(sizeof(laSubProp));
+    ct->FakeProp->Base.SubProp = ct->ExtraProps;
+    ct->FakeProp->Base.Identifier = ct->Identifier->Ptr;
+    ct->FakeProp->Base.PropertyType = LA_PROP_SUB;
+    ct->FakeProp->Base.Offset = offsetof(laUiItem, Extra);
+    ct->FakeProp->Base.OffsetIsPointer = 1;
+    //ut->FakeProp->Base.Container = ut->ExtraProps;
+    return ct->ExtraProps;
+}
+void la_DestroyUiType(laUiType* uit){
+    laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMapper.Items)){ la_FreeKeyMapItem(kmi); }
+    memFree(uit);
+}
+laUiType *la_RegisterUiType(const char *Identifer, int ForType, const char *UseOperator, laBoxedTheme **bt, laUiDrawFunc *Draw, laUiGetHeightFunc GetHeight, laUiInitFunc Init, laUiDestroyFunc Destroy){
+    laUiType *ut = memAcquire(sizeof(laUiType));
+
+    ut->Identifier = Identifer;
+    ut->OperatorID = UseOperator;
+    ut->Draw = Draw;
+    ut->Theme = bt;
+    ut->ForType = ForType;
+    ut->OperatorType = laGetOperatorType(UseOperator);
+    ut->GetHeight = GetHeight;
+    ut->Init = Init;
+    ut->Destroy = Destroy;
+
+    la_UDFAppendSharedTypePointer(Identifer, ut);
+
+    lstAppendItem(&MAIN.UiTypes, ut);
+
+    return ut;
+}
+laUiType *la_GetUiTypeFromProperty(laProp *P){
+    laUiType *ut = MAIN.UiTypes.pFirst;
+    if (!P) return 0;
+    if (P->DefaultUiType) return P->DefaultUiType;
+    if (P->SubProp == LA_PC_SOCKET_IN || P->SubProp == LA_PC_SOCKET_OUT) return _LA_UI_NODE_SOCKET; 
+    if (P->PropertyType == LA_PROP_SUB) return _LA_UI_COLLECTION;
+    for (ut; ut; ut = ut->Item.pNext){
+        if ((ut->ForType&LA_PROP_GENERIC_BITS) == (P->PropertyType&LA_PROP_GENERIC_BITS)){
+            return ut;
+        }
+    }
+    return 0;
+}
+laUiType *la_GetUiButtonType(){
+    laUiType *ut = MAIN.UiTypes.pFirst;
+    for (ut; ut; ut = ut->Item.pNext){
+        if (ut->ForType == LA_PROP_OPERATOR) return ut;
+    }
+    return 0;
+}
+laCanvasTemplate *la_GetCanvasTemplate(char* TargetContainerID, char* TemplateID){
+    laCanvasTemplate *vdt;
+    for (vdt = MAIN.View2DTemplates.pFirst; vdt; vdt = vdt->Item.pNext){
+        if (strSame(TemplateID, vdt->Identifier->Ptr) || strSame(TargetContainerID, vdt->TargetContainerID)) return vdt;
+    }
+    return 0;
+}
+
+void la_AssignPropExtras(laUiItem* ui){
+    if(!ui->Type || !ui->Type->FakeProp) return;
+    ui->FakePs.p = ui->Type->FakeProp;
+    ui->FakePs.Type = L'.';
+    ui->FakePs.UseInstance = ui;
+    ui->ExtraPP.LastPs = &ui->FakePs;
+}
+void la_AssignCanvasPropExtras(laUiItem* ui){
+    if(!ui->CanvasTemplate || !ui->CanvasTemplate->FakeProp) return;
+    laCanvasTemplate*ct=ui->CanvasTemplate;
+    ui->FakePs.p = ct->FakeProp;
+    ui->FakePs.Type = L'.';
+    ui->FakePs.UseInstance = ui;
+    ui->ExtraPP.EndInstance = ui->Extra;
+    ui->ExtraPP.LastPs = &ui->FakePs;
+}
+laUiItem *la_UpdatePropDisplay(laUiItem *ui, laPropPack *Base, const char *Path, laUiDefineFunc Template, laWidget* Widget, char* instructions){
+    int result;
+
+    if (!ui) return;
+
+    laUiType* OverrideType=Widget&&Widget->Type?Widget->Type:0;
+
+    if (Path){
+
+        result = la_GetPropFromPath(&ui->PP, Base, Path, 0);
+
+        if (!result){
+            ui->AT = laGetOperatorType(Path);
+            if (!ui->AT /* && !OverrideType*/) return la_UpdatePropDisplay(ui, 0, "la.example_int", 0, 0, instructions);
+            ui->Type = la_GetUiButtonType();
+            if (OverrideType && (OverrideType->ForType == LA_PROP_OPERATOR)) ui->Type = OverrideType;
+        }else{
+            ui->Type = (OverrideType && ((OverrideType->ForType == ui->PP.LastPs->p->PropertyType) || (OverrideType->TargetSub && !strcmp(OverrideType->TargetSub, ui->PP.LastPs->p->Identifier)))) ? OverrideType : la_GetUiTypeFromProperty(ui->PP.LastPs->p);
+            ui->Flags|=ui->PP.LastPs->p->DefaultFlags;
+        }
+
+        if (Base){
+            ui->PP.RawThis = Base;
+        }
+    }else if (Base){
+        ui->PP.LastPs = Base->LastPs;
+        ui->Type = (OverrideType && ((OverrideType->ForType == ui->PP.LastPs->p->PropertyType) || (OverrideType->TargetSub && !strcmp(OverrideType->TargetSub, ui->PP.LastPs->p->SubProp->Identifier)))) ? OverrideType : la_GetUiTypeFromProperty(ui->PP.LastPs->p);
+        ui->PP.RawThis = Base; //HACK! Not Unified For Prop Access!!!<<<----------??????????
+        ui->Flags|=ui->PP.LastPs->p->DefaultFlags;
+    }
+
+    la_AssignPropExtras(ui);
+
+    if(Widget){ ui->Flags|= Widget->Flags; }
+    if(Template) ui->Template = Template; ui->State = LA_UI_NORMAL;
+    if(!ui->Type) ui->Type = Widget?Widget->Type:0;
+
+    if(instructions) strSafeSet(&ui->ExtraInstructions, instructions);
+
+    return ui;
+}
+laUiItem *la_UpdateLabelDisplay(laUiItem *ui, laUiDefineFunc Template, char *Content){
+    ui->Type = _LA_UI_LABEL;
+
+    ui->Template = Template;
+    ui->State = LA_UI_NORMAL;
+
+    strSafeSet(&ui->Display, Content);
+    la_AssignPropExtras(ui);
+
+    return ui;
+}
+laUiItem *la_CreateGroupHandle(laWidget* Widget){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->Type = (Widget&&Widget->Type)?Widget->Type : _LA_UI_FIXED_GROUP;
+    ui->State = LA_UI_NORMAL;
+    la_AssignPropExtras(ui);
+
+    return ui;
+}
+
+laUiItem *laShowLabel(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    transLate(Content);
+
+    la_UpdateLabelDisplay(ui, Template, Content);
+
+    ui->C = c;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laShowLabelDynamic(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    la_UpdateLabelDisplay(ui, Template, Content);
+
+    ui->C = c;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laShowIcon(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    la_UpdatePropDisplay(ui, Base, Path, 0, Widget, 0);
+    ui->Flags |= LA_UI_FLAGS_INT_ICON;
+    ui->C = c;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laShowItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){
+    return laShowItemFull(uil,c,Base,Path,0,0,0,0);
+}
+laUiItem *laShowItemFull(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget, char* instructions, laUiDefineFunc Template, int TemplateContext){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    la_UpdatePropDisplay(ui, Base, Path, Template, Widget, instructions);
+
+    ui->C = c;
+    ui->TemplateContext = TemplateContext;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laShowNodeSocket(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions){
+    return laShowItemFull(uil,c,Base,Path,LA_WIDGET_NODE_SOCKET,instructions,0,0);
+}
+laUiItem *laShowHeightAdjuster(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions){
+    return laShowItemFull(uil,c,Base,Path,LA_WIDGET_HEIGHT_ADJUSTER,instructions,0,0);
+}
+laUiItem *laShowCanvas(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *id2DTemplate, int Height){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->Type = _LA_UI_CANVAS;
+    ui->State = LA_UI_NORMAL;
+    ui->C = c;
+
+    la_GetPropFromPath(&ui->PP, Base, Path, 0);
+
+    if (id2DTemplate) ui->CanvasTemplate = la_GetCanvasTemplate(0, id2DTemplate);
+    else{
+        if(!ui->PP.LastPs || ui->PP.LastPs->p->PropertyType!=LA_PROP_SUB){ la_FreePropStepCache(ui->PP.Go); memFree(ui); return laShowItem(uil,c,Base,Path); }
+        laSubProp* sp=ui->PP.LastPs->p; ui->PP.LastPs->p->SubProp=la_EnsureSubTarget(sp,0);
+        ui->CanvasTemplate = la_GetCanvasTemplate(sp->TargetID, 0);
+        if(!ui->CanvasTemplate){ la_FreePropStepCache(ui->PP.Go); memFree(ui); return laShowItem(uil,c,Base,Path); }
+    }
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    la_AssignCanvasPropExtras(ui);
+
+    if (Height) ui->Expand=Height; else ui->Expand=6;
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laShowColumnAdjuster(laUiList *uil, laColumn *c){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+    laCanvasExtra *e;
+
+    ui->Type = _LA_UI_COLUMN_ADJUSTER;
+    ui->Flags |= LA_WIDGET_COLUMN_ADJUSTER->Flags;
+
+    ui->C = c;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laShowSymbol(laUiList *uil, laColumn *c, int SymbolID, int Height){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->Type = _LA_UI_SYMBOL;
+
+    ui->SymbolID = SymbolID;
+    if (Height) ui->State = Height;
+
+    ui->C = c;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+
+laUiItem *laBeginRow(laUiList *uil, laColumn *c, int Expand, int Even){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->Type = &_LA_UI_ROW_BEGIN;
+
+    ui->State=Expand;
+    ui->Flags=Even;
+    ui->C = c;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    lstAppendItem(&uil->UiItems, ui);
+    return ui;
+}
+laUiItem *laEndRow(laUiList *uil, laUiItem* Begin){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->Type = &_LA_UI_ROW_END;
+    ui->C = Begin->C;
+    ui->Page = (laUiList*)Begin;
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    lstAppendItem(&uil->UiItems, ui);
+    return ui;
+}
+
+
+void la_ConditionerInit(laUiItem *ui, laUiConditionNode *Expression){
+    laConditionUiExtraData *e = CreateNew(laConditionUiExtraData);
+    e->Expression = Expression;
+    ui->Extra = e;
+    la_AssignPropExtras(ui);
+}
+
+laUiItem *laMakeGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget){
+    laUiItem *ui = la_CreateGroupHandle(Widget);
+    laUiList *nuil;
+
+    ui->C = c;
+    lstAppendItem(&uil->UiItems, ui);
+
+    nuil = memAcquireSimple(sizeof(laUiList));
+    strSafeSet(&nuil->TabName, Name);
+    ui->Page = nuil;
+    lstAppendItem(&ui->Subs, nuil);
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    return ui;
+}
+laUiItem *laMakeFoldableGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget, int DefaultFolded){
+    laUiItem *SubUi = laMakeGroup(uil, c, Name, Widget?Widget:0);
+    laUiList *sub = SubUi->Page;
+    laColumn *s = laFirstColumn(sub);
+    SubUi->State = LA_UI_ACTIVE;
+
+    laUiItem *b1 = laOnConditionToggle(sub, s, 0, 0, 0, 0, 0);
+    strSafePrint(&b1->ExtraInstructions, "text=%s", Name);
+    if(!DefaultFolded) b1->State=LA_UI_ACTIVE;
+    b1->Flags|=LA_UI_FLAGS_NO_DECAL;
+    laShowSeparator(sub, s);
+    return SubUi;
+}
+laUiItem *laMakeEmptyGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget){
+    laUiItem *SubUi = laMakeGroup(uil, c, Name, Widget?Widget->Type:0);
+    laUiList *sub = SubUi->Page;
+    laColumn *s = laFirstColumn(sub);
+    SubUi->State = LA_UI_ACTIVE;
+    return SubUi;
+}
+void laEndFoldableGroup(laUiList *sub, laUiItem *group){
+    laEndCondition(sub, sub->UiItems.pFirst);
+}
+laUiItem *laMakeTab(laUiList *uil, laColumn *c, laWidget* Widget){
+    laUiItem *ui = la_CreateGroupHandle(Widget?Widget:LA_WIDGET_TAB);
+    laUiList *nuil;
+
+    ui->C = c;
+    lstAppendItem(&uil->UiItems, ui);
+
+    if (ui->Type->Init) ui->Type->Init(ui);
+    ui->ExtraPP.EndInstance = ui->Extra;
+    
+    return ui;
+}
+laUiList *laAddTabPage(laUiItem *ui, const char *Name){
+    laUiList *uil = memAcquireSimple(sizeof(laUiList));
+
+    if (!ui->Page) ui->Page = uil;
+    lstAppendItem(&ui->Subs, uil);
+    strSafeSet(&uil->TabName, Name);
+    laFirstColumn(uil);
+
+    //laFirstColumn(uil);
+
+    return uil;
+}
+laUiList *laAddTabPageInternal(laUiItem *ui, const char *Name){
+    laUiList *uil = memAcquireSimple(sizeof(laUiList));
+
+    if (!ui->Page) ui->Page = uil;
+    lstAppendItem(&ui->Subs, uil);
+    strSafeSet(&uil->TabName, Name);
+
+    //laFirstColumn(uil);
+
+    return uil;
+}
+laUiList *la_AddInstancePage(laUiItem *ui, void *Instance, laWidget* Widget){
+    laUiList *uil = memAcquireSimple(sizeof(laUiList));
+
+    /*if (!ui->Page) */ ui->Page = uil;
+    lstAppendItem(&ui->Subs, uil);
+    uil->Instance = Instance; ui->PP.EndInstance=Instance;
+
+    return uil;
+}
+laUiConditionNode *laTrue(){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_TRUE;
+    return ucn;
+}
+laUiConditionNode *laFalse(){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_FALSE;
+    return ucn;
+}
+laUiConditionNode *laPropExpression(laPropPack *Base, char *Prop){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_PROP;
+    la_GetPropFromPath(&ucn->PP, Base, Prop, 0);
+    strSafeSet(&ucn->String, Prop);
+    return ucn;
+}
+laUiConditionNode *laIntExpression(int Value){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_INT;
+    ucn->IntValue = Value;
+    return ucn;
+}
+laUiConditionNode *laFloatExpression(real Value){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_FLOAT;
+    ucn->FloatValue = Value;
+    return ucn;
+}
+laUiConditionNode *laStringExpression(char *Content){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_STRING;
+    strSafeSet(&ucn->String, Content);
+    return ucn;
+}
+laUiConditionNode *laAnd(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_AND;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+laUiConditionNode *laOr(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_OR;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+laUiConditionNode *laNot(laUiConditionNode *Expression1){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_NOT;
+    ucn->Expression1 = Expression1;
+    return ucn;
+}
+laUiConditionNode *laEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_EQ;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+laUiConditionNode *laGreaterThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_GT;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+laUiConditionNode *laLessThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_LT;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+laUiConditionNode *laGreaterEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_GE;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+laUiConditionNode *laLessEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){
+    laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode));
+    ucn->Type = LA_CONDITION_LE;
+    ucn->Expression1 = Expression1;
+    ucn->Expression2 = Expression2;
+    return ucn;
+}
+int la_GetIntConditionValue(laUiConditionNode *Expression){
+    if (Expression->Type != LA_CONDITION_INT) return 0;
+    return Expression->Expression1;
+}
+real la_GetFloatConditionValue(laUiConditionNode *Expression){
+    if (Expression->Type != LA_CONDITION_FLOAT) return 0;
+    return Expression->FloatValue;
+}
+char *la_GetStringConditionValue(laUiConditionNode *Expression){
+    return Expression->String->Ptr;
+}
+int la_DoCompare(int CompMode, int Mode1, int i1, real f1, char *s1, void *p1, int Mode2, int i2, real f2, char *s2, void *p2){
+    switch (Mode1){
+    case LA_PROP_ENUM:
+    case LA_PROP_INT:
+    case LA_CONDITION_INT:
+        switch (Mode2){
+        case LA_PROP_ENUM:
+        case LA_PROP_INT:
+        case LA_CONDITION_INT:
+            switch (CompMode){
+            case LA_CONDITION_GE:
+                return (i1 >= i2);
+            case LA_CONDITION_GT:
+                return (i1 > i2);
+            case LA_CONDITION_EQ:
+                return (i1 == i2);
+            case LA_CONDITION_LT:
+                return (i1 < i2);
+            case LA_CONDITION_LE:
+                return (i1 <= i2);
+            }
+        case LA_PROP_FLOAT:
+        case LA_CONDITION_FLOAT:
+            switch (CompMode){
+            case LA_CONDITION_GE:
+                return ((real)i1 >= f2);
+            case LA_CONDITION_GT:
+                return ((real)i1 > f2);
+            case LA_CONDITION_EQ:
+                return ((real)i1 >= f2 - 0.0001 && (real)i1 <= f2 + 0.0001);
+            case LA_CONDITION_LT:
+                return ((real)i1 < f2);
+            case LA_CONDITION_LE:
+                return ((real)i1 <= f2);
+            }
+        case LA_PROP_SUB:
+            if (CompMode == LA_CONDITION_EQ) return i1 == (int)p2;
+        default:
+            return 0;
+        }
+    case LA_PROP_FLOAT:
+    case LA_CONDITION_FLOAT:
+        switch (Mode2){
+        case LA_PROP_INT:
+        case LA_PROP_ENUM:
+        case LA_CONDITION_INT:
+            switch (CompMode){
+            case LA_CONDITION_GE:
+                return (f1 >= (real)i2);
+            case LA_CONDITION_GT:
+                return (f1 > (real)i2);
+            case LA_CONDITION_EQ:
+                return (f1 + 0.0001 >= (real)i2 && f1 - 0.0001 <= (real)i2);
+            case LA_CONDITION_LT:
+                return (f1 < (real)i2);
+            case LA_CONDITION_LE:
+                return (f1 <= (real)i2);
+            }
+        case LA_PROP_FLOAT:
+        case LA_CONDITION_FLOAT:
+            switch (CompMode){
+            case LA_CONDITION_GE:
+                return (f1 >= f2);
+            case LA_CONDITION_GT:
+                return (f1 > f2);
+            case LA_CONDITION_EQ:
+                return (f1 == f2);
+            case LA_CONDITION_LT:
+                return (f1 < f2);
+            case LA_CONDITION_LE:
+                return (f1 <= f2);
+            }
+        default:
+            return 0;
+        }
+    case LA_PROP_STRING:
+    case LA_CONDITION_STRING:
+        switch (Mode2){
+        case LA_PROP_STRING:
+        case LA_CONDITION_STRING:
+            return strSame(s1, s2);
+        default:
+            return 0;
+        }
+    case LA_PROP_SUB:
+        switch (Mode2){
+        case LA_PROP_SUB:
+            return p1 == p2;
+        case LA_CONDITION_INT:
+        case LA_PROP_INT:
+        case LA_PROP_ENUM:
+            return (int)p1 == i2;
+        default:
+            return 0;
+        }
+    default:
+        switch (CompMode){
+        case LA_CONDITION_GE:
+            return (i1 >= i2);
+        case LA_CONDITION_GT:
+            return (i1 > i2);
+        case LA_CONDITION_EQ:
+            return (i1 == i2);
+        case LA_CONDITION_LT:
+            return (i1 < i2);
+        case LA_CONDITION_LE:
+            return (i1 <= i2);
+        }
+    }
+}
+int la_DoExpression(laUiConditionNode *Expression, int *IResult, real *FResult, char *_StrResult, void **PtrResult){
+    void *Instance = 0;
+    int IValue1 = 0, IValue2 = 0;
+    real FValue1 = 0, FValue2 = 0;
+    void *Ptr1 = 0, *Ptr2 = 0;
+    char Str1[128], Str2[128]={0}; char* StrResult=_StrResult;
+    int Result1, Result2;
+    laEnumItem *ei;
+
+    if (!Expression) return 0;
+
+    Str1[0] = 0;
+    Str2[0] = 0;
+
+    laPropIterator pi = {0};
+
+    switch (Expression->Type){
+    case LA_CONDITION_PROP:
+        if (!Expression->PP.LastPs){
+            (*IResult) = 0;
+            return 0;
+        }
+        switch (Expression->PP.LastPs->p->PropertyType){
+        case LA_PROP_INT:
+            *IResult = laGetInt(&Expression->PP);
+            if (*IResult) return LA_CONDITION_INT;
+            else
+                return 0;
+        case LA_PROP_FLOAT:
+            *FResult = laGetFloat(&Expression->PP);
+            if (*FResult) return 1;
+            else
+                return 0;
+            break;
+        case LA_PROP_STRING:
+            laGetString(&Expression->PP, _StrResult, &StrResult);
+            if (StrResult[0]) return 1;
+            else
+                return 0;
+            break;
+        case LA_PROP_ENUM:
+            ei = laGetEnum(&Expression->PP);
+            if (!ei) return 0;
+            /*if(ei) */ *IResult = ei->Index;
+            if (*IResult) return LA_CONDITION_INT;
+            break;
+        case LA_PROP_SUB:
+            if (!Expression->PP.Go) Instance = Expression->PP.EndInstance;
+            else
+                Instance = laGetActiveInstance(Expression->PP.LastPs->p, Expression->PP.LastPs->UseInstance, &pi);
+            *PtrResult = Instance;
+            if (Instance) return 1;
+            break;
+        default:
+            return 0;
+        }
+    case LA_CONDITION_INT:
+        *IResult = Expression->IntValue;
+        if (*IResult) return 1;
+        else
+            return 0;
+    case LA_CONDITION_FLOAT:
+        *FResult = Expression->FloatValue;
+        if (*FResult) return 1;
+        else
+            return 0;
+    case LA_CONDITION_STRING:
+        if (Expression->String){
+            strCopyFull(StrResult, Expression->String->Ptr);
+            return 1;
+        }else
+            return 0;
+    case LA_CONDITION_TRUE:
+        if (*IResult) *IResult = 1;
+        return 1;
+    case LA_CONDITION_FALSE:
+        if (*IResult) *IResult = 0;
+        return 0;
+    default:
+        Result1 = la_DoExpression(Expression->Expression1, &IValue1, &FValue1, &Str1, &Ptr1);
+        switch (Expression->Type){
+        case LA_CONDITION_AND:
+            if (Result1){
+                Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2);
+                if (Result2) *IResult = 1;
+                return (Result2);
+            }else
+                return 0;
+        case LA_CONDITION_OR:
+            if (!Result1){
+                Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2);
+                if (Result2) *IResult = 1;
+                return (Result2);
+            }else
+                return 1;
+        case LA_CONDITION_NOT:
+            return !Result1;
+        default:
+            Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2);
+            return la_DoCompare(Expression->Type,
+                                 (Expression->Expression1->Type == LA_CONDITION_PROP && Expression->Expression1->PP.LastPs) ? Expression->Expression1->PP.LastPs->p->PropertyType : Expression->Expression1->Type, IValue1, FValue1, Str1, Ptr1,
+                                 (Expression->Expression2->Type == LA_CONDITION_PROP && Expression->Expression2->PP.LastPs) ? Expression->Expression2->PP.LastPs->p->PropertyType : Expression->Expression2->Type, IValue2, FValue2, Str2, Ptr2);
+        }
+        break;
+    }
+    return 0;
+}
+int la_DoSingleExpression(laUiConditionNode *Expression){
+    int a;
+    real b;
+    char c[128]={0};
+    void *p;
+
+    if (!Expression) return 1;
+
+    c[0] = 0;
+
+    return la_DoExpression(Expression, &a, &b, c, &p);
+}
+void la_StepExpression(laUiConditionNode *e){
+    if (!e) return;
+    switch (e->Type){
+    case LA_CONDITION_AND:
+    case LA_CONDITION_OR:
+    case LA_CONDITION_GE:
+    case LA_CONDITION_GT:
+    case LA_CONDITION_EQ:
+    case LA_CONDITION_LT:
+    case LA_CONDITION_LE:
+        la_StepExpression(e->Expression1);
+        la_StepExpression(e->Expression2);
+        break;
+    case LA_CONDITION_NOT:
+        la_StepExpression(e->Expression1);
+        break;
+    case LA_CONDITION_PROP:
+        la_StopUsingPropPack(&e->PP);
+        la_StepPropPack(&e->PP);
+        if (e->PP.LastPs && e->PP.LastPs->p->Container && e->PP.LastPs->p->Container->Hyper){
+            la_UsePropPack(&e->PP, 1);
+            //laUseDataBlock(e->PP.Go ? e->PP.LastPs->UseInstance : e->PP.EndInstance, e->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover,1);
+        }
+        break;
+    default:
+        break;
+    }
+}
+void la_ConditionNodeFreeRecursive(laUiConditionNode *ucn){
+    if (!ucn) return;
+    la_ConditionNodeFreeRecursive(ucn->Expression1);
+    la_ConditionNodeFreeRecursive(ucn->Expression2);
+    if (ucn->PP.LastPs) la_FreePropStepCache(ucn->PP.Go);
+    if (ucn->String) strSafeDestroy(&ucn->String);
+    if (ucn) memFree(ucn);
+}
+
+laUiItem *laOnConditionThat(laUiList *uil, laColumn *c, laUiConditionNode *Expression){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->C = c;
+    ui->Type = &_LA_UI_CONDITION;
+    la_ConditionerInit(ui, Expression);
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laElse(laUiList *uil, laUiItem *Beginner){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+    laConditionUiExtraData *cued;
+
+    ui->Type = &_LA_UI_CONDITION_ELSE;
+
+    la_ConditionerInit(ui, 0);
+    cued = ui->Extra;
+
+    cued->EndUi = Beginner;
+    ((laConditionUiExtraData *)Beginner->Extra)->ElseUi = ui;
+
+    ui->C = Beginner->C;
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laOnConditionToggle(laUiList *uil, laColumn *col, laUiDefineFunc define, int Remove, laPropPack *ExtraBase, laPropPack *ExtraThis, laWidget* Widget){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+    laConditionUiExtraData *cued;
+
+    ui->Template = define;
+    ui->C = col;
+    ui->PP.RawThis = ExtraBase;
+    ui->Page = ExtraThis;
+    ui->Type = Widget? Widget->Type : _LA_UI_CONDITION_TOGGLE;
+
+    la_ConditionerInit(ui, 0);
+
+    cued = ui->Extra;
+    //cued->Remove = Remove;
+
+    ui->State = LA_UI_NORMAL;
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiItem *laEndCondition(laUiList *uil, laUiItem *Beginner){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+    laConditionUiExtraData *cued;
+
+    ui->Type = &_LA_UI_CONDITION_END;
+
+    la_ConditionerInit(ui, 0);
+    cued = ui->Extra;
+
+    cued->EndUi = Beginner;
+    ((laConditionUiExtraData *)Beginner->Extra)->EndUi = ui;
+
+    ui->C = Beginner->C;
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+laUiList *laMakeMenuPage(laUiList *uil, laColumn *c, const char *Title){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+    laUiList *muil = memAcquireSimple(sizeof(laUiList));
+
+    ui->Type = _LA_UI_MENU_ROOT;
+    strSafeSet(&ui->Display, Title);
+    ui->State = LA_UI_NORMAL;
+    ui->C = c;
+    lstAppendItem(&uil->UiItems, ui);
+
+    lstAppendItem(&ui->Subs, muil);
+
+    return muil;
+}
+laUiItem *laShowSeparator(laUiList *uil, laColumn *widest){
+    laUiItem *ui = memAcquireSimple(sizeof(laUiItem));
+
+    ui->Type = _LA_UI_ALIGN;
+    ui->C = widest;
+
+    lstAppendItem(&uil->UiItems, ui);
+
+    return ui;
+}
+void laFixHeight(laUiList *uil, short Rows){
+    if (!uil) return;
+    uil->HeightCoeff = Rows;
+}
+
+int la_GetUiType(laUiItem* ui) {
+	if (ui->AT) return LA_UI_INTERNAL_BUTTON;
+
+	if (ui->PP.LastPs) {
+		if (ui->Type == _LA_UI_CANVAS) return LA_UI_INTERNAL_2D_VIEW;
+		return LA_UI_INTERNAL_WATCHER;
+	}
+	if (ui->Display) {
+		if (ui->Type == _LA_UI_MENU_ROOT) return LA_UI_INTERNAL_MENU;
+		return LA_UI_INTERNAL_LABEL;
+	}
+
+	if (ui->Subs.pFirst) {
+		if (ui->Type == _LA_UI_FIXED_GROUP)return LA_UI_INTERNAL_GROUP;
+		if (ui->Type == _LA_UI_TAB)return LA_UI_INTERNAL_TAB;
+		return LA_UI_INTERNAL_GROUP;
+	}
+
+	if (ui->Type == _LA_UI_BUTTON) return LA_UI_INTERNAL_BUTTON;
+	
+	if (ui->Type == &_LA_UI_CONDITION) return LA_UI_INTERNAL_BRACKET_BEGIN;
+	if (ui->Type == &_LA_UI_CONDITION_ELSE) return LA_UI_INTERNAL_BRACKET_ELSE;
+	if (ui->Type == &_LA_UI_CONDITION_END) return LA_UI_INTERNAL_BRACKET_END;
+	if (ui->Type == _LA_UI_CONDITION_TOGGLE) return LA_UI_INTERNAL_FOLDER_BEGIN;
+
+	if (ui->Type == _LA_UI_ALIGN) return LA_UI_INTERNAL_ALIGNER;
+	if (ui->Type == _LA_UI_COLUMN_ADJUSTER) return LA_UI_INTERNAL_ADJUSTER;
+	if (ui->Type == _LA_UI_SYMBOL) return LA_UI_INTERNAL_SYMBOL;
+
+	return LA_UI_INTERNAL_WATCHER;
+}
+
+void laMakeUiListFromTemplate(laUiList *Into, laUiDefineFunc Template,
+                               laPropPack *PanelPP, laPropPack *PanelExtraPP, laPropPack *Base, laPropPack *Operator, laListHandle *ExtraColumns, int Context){
+    if (!ExtraColumns) return;
+    Template(Into, Base, Operator, ExtraColumns->pFirst, Context);
+}
+laUiTemplate *laFindUiTemplate(char *Identifier){
+    laUiTemplate *uit;
+    for (uit = MAIN.PanelTemplates.pFirst; uit; uit = uit->Item.pNext){
+        if (!strcmp(uit->Identifier->Ptr, Identifier)) return uit;
+    }
+    return 0;
+}
+
+void la_DestroyUiTemplate(laUiTemplate* uit){
+    strSafeDestroy(&uit->Identifier);
+    strSafeDestroy(&uit->Title);
+    laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMap.Items)){ la_FreeKeyMapItem(kmi); }
+    memFree(uit);
+}
+void la_DestroyCanvasTemplate(laCanvasTemplate* uit){
+    strSafeDestroy(&uit->Identifier);
+    laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMapper.Items)){ la_FreeKeyMapItem(kmi); }
+    memFree(uit);
+}
+laUiTemplate *laRegisterUiTemplate(char *Identifier, char* Title, laUiDefineFunc func,laPanelDetachedPropFunc PropFunc, laUiDefineFunc header){
+    laUiTemplate *uit = memAcquire(sizeof(laUiTemplate));
+    strSafeSet(&uit->Identifier, Identifier);
+    strSafeSet(&uit->Title, Title);
+    uit->Define = func;
+    uit->Header = header;
+    uit->PropFunc = PropFunc;
+    lstAppendItem(&MAIN.PanelTemplates, uit);
+    la_UDFAppendSharedTypePointer(Identifier, uit);
+    return uit;
+}
+laCanvasTemplate *laRegisterCanvasTemplate(char *Identifier, char *ForContainer, laCanvasDrawFunc Func, laUiDrawFunc SecondDraw, laUiInitFunc CustomInit, laUiDestroyFunc CustomDestroy){
+    laCanvasTemplate *t = memAcquire(sizeof(laCanvasTemplate));
+    strSafeSet(&t->Identifier, Identifier);
+    t->Draw = Func; t->SecondDraw = SecondDraw; t->TargetContainerID = ForContainer;
+    t->Init = CustomInit; t->Destroy = CustomDestroy;
+    lstAppendItem(&MAIN.View2DTemplates, t);
+    la_UDFAppendSharedTypePointer(Identifier, t);
+    return t;
+}
+void laFinalizeUiTemplates(){
+    laUiTemplate *uit;
+    laCanvasTemplate *u2d;
+    for (u2d = MAIN.View2DTemplates.pFirst; u2d; u2d = u2d->Item.pNext){
+        if (u2d->TargetContainerID) u2d->TargetContainer = la_ContainerLookup(u2d->TargetContainerID);
+    }
+}
+
+laPanel *la_FindFreePanelByTemplate(laWindow *w, const laUiTemplate *uit){
+    laPanel *p;
+    for (p=w->Panels.pFirst; p; p = p->Item.pNext){
+        if (p->PanelTemplate==uit){
+            return p;
+        }
+    }
+    return 0;
+}
+void la_DestroyUiItem(laUiItem *ui, int RemoveUsers){
+    laUiList *uil, *NextUil;
+    for (uil = ui->Subs.pFirst; uil; uil = NextUil){
+        NextUil = uil->Item.pNext;
+        lstRemoveItem(&ui->Subs, uil);
+        la_DestroyUiList(uil, 0, RemoveUsers, 0);
+    }
+    la_StopUiOperatorService(ui);
+    strSafeDestroy(&ui->ExtraInstructions);
+    strSafeDestroy(&ui->Display);
+    if (RemoveUsers && ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper)
+        la_StopUsingPropPack(&ui->PP);
+        //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP);
+    la_FreePropStepCache(ui->PP.Go); //-------[Up Here], instance already been freed.XXXXXXXXXXXX!!!!!!!!!!1
+    if (ui->Type->Destroy) ui->Type->Destroy(ui);
+    memFree(ui);
+}
+void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemoveUser){
+    laUiItem *ui, *NextUi;
+    laColumn *col, *NextCol;
+    if (!uil) return;
+    for (ui = uil->UiItems.pFirst; ui; ui = NextUi){
+        NextUi = ui->Item.pNext;
+        if(OnlyRemoveUser && RemoveUsers){
+            if (ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper)
+                la_StopUsingPropPack(&ui->PP);
+                //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP);
+            continue;
+        }
+        lstRemoveItem(&uil->UiItems, ui);
+        la_DestroyUiItem(ui, RemoveUsers);
+    }
+    if(OnlyRemoveUser){ return; }
+    for (col = uil->Columns.pFirst; col; col = NextCol){
+        NextCol = col->Item.pNext;
+        lstRemoveItem(&uil->Columns, col);
+        memFree(col);
+    }
+
+    strSafeDestroy(&uil->TabName);
+
+    if (!NoFree) memFree(uil);
+}
+void la_DestroyTabPage(laUiItem *ui, laUiList *Tab, int RemoveUsers){
+    lstRemoveItem(&ui->Subs, Tab);
+    la_DestroyUiList(Tab, 1, RemoveUsers, 0);
+}
+void la_CreateUiAfter(laUiList *uil, laUiItem *after, laUiDefineFunc Define, laPropPack *Base, laPropPack *This, laColumn **ExtraColums){
+    laUiItem *Next = after->Item.pNext;
+    laUiItem *Last = uil->UiItems.pLast;
+    after->Item.pNext = 0;
+    uil->UiItems.pLast = after;
+
+    Define(uil, Base, This, ExtraColums, 0);
+
+    if (Next) Next->Item.pPrev = uil->UiItems.pLast;
+    ((laUiItem *)uil->UiItems.pLast)->Item.pNext = Next;
+    if (Next != Last) uil->UiItems.pLast = Last;
+}
+//void la_RefreshExtraColumns(laUiItem* ui, int B,int FromL,int ToL,int FromR,int ToR){
+//	int i = 0;
+//	int FromW=FromR-FromL, ToW=ToR-ToL;
+//	if (!ui->ExtraColums) return;
+//	for (i; ui->ExtraColums[i]; i++) {
+//		laColumn* c = ui->ExtraColums[i];
+//		c->B = B;
+//		c->IL = (c->IL - FromL) / FromW*ToW + ToL;
+//		c->IR = (c->IR - FromL) / FromW*ToW + ToL;
+//	}
+//}
+void la_PropPanelUserRemover(void* this_UNUSED, laItemUserLinker* iul){
+    laPanel* p = iul->Pointer.p; if(p->FrameDistinguish == iul->FrameDistinguish){ p->Refresh |= LA_TAG_RECALC; }
+}
+void la_CalcUiItemInfluence(laListHandle *lst, laUiItem *ui){
+    laColumn *c = ui->C;
+    laColumn *ic = lst->pFirst;
+
+    c->B = ui->TB + (*ui->Type->Theme)->BP;
+
+    for (ic; ic; ic = ic->Item.pNext){
+        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){
+            ic->B = ic->B < c->B ? c->B : ic->B;
+        }
+    }
+    ic = ui->C;
+    while (ic->Item.pPrev && (ic = ic->Item.pPrev))
+        ;
+    for (ic; ic; ic = ic->Item.pNext){
+        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){
+            ic->B = ic->B < c->B ? c->B : ic->B;
+        }
+    }
+}
+void la_CalcUiTopInfluence(laListHandle *lst, laUiItem *ui){
+    laColumn *c = ui->C;
+    laColumn *ic = lst->pFirst;
+
+    c->B = ui->TB + (*ui->Type->Theme)->TP;
+
+    for (ic; ic; ic = ic->Item.pNext){
+        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){
+            ic->B = ic->B < c->B ? c->B : ic->B;
+        }
+    }
+    ic = ui->C;
+    while (ic->Item.pPrev && (ic = ic->Item.pPrev))
+        ;
+    for (ic; ic; ic = ic->Item.pNext){
+        if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){
+            ic->B = ic->B < c->B ? c->B : ic->B;
+        }
+    }
+}
+int la_ResetUiColum(laColumn *c, laColumn *Top, int U, int L, int R, int LR, int repos){ //1=L,2=R
+    int rep;
+    int sp;
+    int rev;
+
+    if (!c) return 0;
+
+    sp = (c->SP * (R - L)) + L;
+    rev = sp;
+
+    /*if (U)*/ c->B = U;
+
+    if (LR == 1){
+        c->IL = L;
+        c->IR = sp;
+        if (repos){
+            c->IR = repos;
+        }else if (c->MaxW*LA_RH && c->IR - c->IL > c->MaxW*LA_RH){
+            c->IR = c->IL + c->MaxW*LA_RH;
+            rev = c->IR;
+        }
+    }else if (LR == 2){
+        c->IL = sp;
+        c->IR = R;
+        if (repos){
+            c->IL = repos;
+        }else if (c->MaxW*LA_RH && c->IR - c->IL > c->MaxW*LA_RH){
+            c->IL = c->IR - c->MaxW*LA_RH;
+            rev = c->IL;
+        }
+    }else if (LR == 0){
+        c->IL = L;
+        c->IR = R;
+    }
+
+    if (c->LS && c->RS->MaxW == 0){
+        rep = la_ResetUiColum(c->LS, Top, U, c->IL, c->IR, 1, 0);
+        la_ResetUiColum(c->RS, Top, U, c->IL, c->IR, 2, rep);
+        c->LS->PreWidth = c->PreWidth * c->LS->SP;
+        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);
+    }else if (c->RS && c->LS->MaxW == 0){
+        rep = la_ResetUiColum(c->RS, Top, U, c->IL, c->IR, 2, 0);
+        la_ResetUiColum(c->LS, Top, U, c->IL, c->IR, 1, rep);
+        c->LS->PreWidth = c->PreWidth * c->LS->SP;
+        c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP);
+    }
+
+    return rev;
+}
+
+STRUCTURE(laRowInfo){
+    int MaxW;
+    int MinW;
+    int UnitMinW;
+    int NonExpandW;
+    int TotalPadding;
+    int Expand, Even;
+    int ExpandAccum;
+    int CountElements;
+    int U,MaxB,L;
+    laListHandle Elements;
+};
+STRUCTURE(laRowNode){
+    laListItem Item;
+    laUiItem* ui;
+    int GotW, LP, RP, H;
+    int Expand;
+};
+int la_InitRowNode(laRowInfo* ri, laUiItem* ui, laBoxedTheme* bt){
+    ri->MaxW = ui->TR-ui->TL;//row node does not use margin
+    ri->UnitMinW=LA_RH+bt->LM+bt->RM;
+    ri->Expand=ui->State?1:0;
+    ri->Even=ui->Flags?1:0;
+    ri->U=ui->TU; ri->L=ui->TL;
+    ri->MaxB=ui->TU;
+}
+int la_AddRowNode(laRowInfo* ri, laUiItem* ui, laBoxedTheme* bt, int H){
+    laRowNode* rn=CreateNew(laRowNode);
+    rn->LP=bt->LP;rn->RP=bt->RP;
+    rn->GotW = (ui->Type->GetMinWidth?ui->Type->GetMinWidth(ui):(LA_RH)) +bt->LM+bt->RM;
+    rn->ui=ui;
+    rn->H=H;
+    rn->Expand=ui->Expand;
+    lstAppendItem(&ri->Elements, rn);
+
+    if(!ri->UnitMinW){ri->UnitMinW=LA_RH+bt->LM+bt->RM;}
+    ri->TotalPadding += bt->LP+bt->RP;
+    ri->MinW+=ri->UnitMinW;
+    ri->NonExpandW+=rn->GotW;
+    ri->ExpandAccum+=ui->Expand;
+    ri->CountElements++;
+    if(ui->Expand){ri->Expand=1;}
+    if(ri->U+H+bt->BP>ri->MaxB){ri->MaxB=ri->U+H+bt->BP;}
+}
+int la_ShrinkableRowElements(laRowInfo* ri){
+    int count=0;
+    for(laRowNode* rn=ri->Elements.pFirst;rn;rn=rn->Item.pNext){
+        if(rn->GotW<=ri->UnitMinW) continue;
+        count++;
+    }
+    return count;
+}
+int la_CalculateRowExpand(laRowInfo* ri, laUiItem* ui_end, int WaitAnimation){
+    int Available=ri->MaxW-ri->NonExpandW-ri->TotalPadding;
+    int ShareCount=0, Additional=0, AdditionalRemaining=0, Shrinkable=0; real NodeAddFraction=0;
+    if(Available<0){
+        ShareCount=1;// Shrinkable=la_ShrinkableRowElements(ri);
+        Additional=(ri->MaxW-ri->MinW-ri->TotalPadding)/ri->CountElements;
+        AdditionalRemaining = (ri->MaxW-ri->MinW-ri->TotalPadding)-Additional*ri->CountElements;
+    }else{
+        if(!ri->Expand && Available>0){Available=0;}
+        ShareCount=ri->ExpandAccum?ri->ExpandAccum:ri->CountElements;
+    }
+    if(!ShareCount) return;
+    int PerNode = Available/ShareCount;
+    int Remaining = Available-PerNode*ShareCount;
+    int L = ri->L; int i=0; laRowNode* rn;
+
+    for(rn=ri->Elements.pFirst;rn;rn=rn->Item.pNext){
+        laUiItem* ui=rn->ui;
+        int NodeAdd, Node=rn->GotW;
+        if(Available>=0){
+            NodeAdd=ri->ExpandAccum?(PerNode*rn->Expand):PerNode;
+            NodeAdd+=(i<Remaining?1:0);i++;
+        }else{
+            if(ri->MaxW>=ri->MinW+ri->TotalPadding) {
+                NodeAddFraction+=((rn->GotW>ri->UnitMinW)?(real)Available*(real)(rn->GotW-ri->UnitMinW)/(real)(ri->NonExpandW-ri->MinW):0);
+                NodeAdd=(int)NodeAddFraction; NodeAddFraction-=NodeAdd;
+            }else{ Node=ri->UnitMinW;
+                NodeAdd=Additional+(i<-AdditionalRemaining?-1:0);i++;
+            }
+        }
+        ui->TL = L + rn->LP;
+        ui->TR = ui->TL + Node+NodeAdd;
+        ui->TB = ui->TU + rn->H;
+        L=ui->TR+rn->RP;
+        if (!WaitAnimation){
+            ui->L = ui->TL; ui->R = ui->TR;
+            ui->U = ui->TU; ui->B = ui->TB;
+        }
+        if(ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocketRuntimePosition(ui); }
+    }
+    ui_end->TB = ri->MaxB;
+    while(rn=lstPopItem(&ri->Elements)){
+        FreeMem(rn);
+    }
+    memset(ri, 0, sizeof(laRowInfo));
+}
+void la_RecordSocketRuntimePosition(laUiItem* ui){
+    laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);
+    if(pc==LA_PC_SOCKET_OUT){
+        laNodeOutSocket* s=ui->PP.EndInstance; s->RuntimeX=(ui->TL+ui->TR)/2; s->RuntimeY=(ui->TU+ui->TB)/2;
+    }else{
+        laNodeInSocket* s=ui->PP.EndInstance;  s->RuntimeX=(ui->TL+ui->TR)/2; s->RuntimeY=(ui->TU+ui->TB)/2;
+    }
+}
+int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast, laPanel *ParentPanel){
+    laUiItem *ui;
+    laBoxedTheme *bt;
+    int Lowest = 0;
+    int HyperValue = 0;
+    int WaitAnimation;
+    int RowMode=0; laRowInfo ri={0};
+    laBoxedTheme* pt=*(ParentPanel->BT);
+    int _PL=-pt->LM,_PR=-pt->RM,_PT=-pt->TM,_PB=-pt->BM;
+    int MaxR=0;
+
+    if(!uil->Scale){uil->Scale=1;}
+    uil->SaveScale=MAIN.UiScale;
+    MAIN.UiScale*=uil->Scale;
+    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;
+
+    uil->TU = U;uil->TL = L;uil->TR = R;uil->TB = uil->TU;
+    WaitAnimation = 0;
+
+    if (!uil->Columns.pFirst && !uil->UiItems.pFirst) return U;
+
+    la_ResetUiColum(uil->Columns.pFirst, uil->Columns.pFirst, U, L, R, 0, 0);
+
+    for (ui = uil->UiItems.pFirst; ui;){
+        int SubB = 0;
+        int H;
+        WaitAnimation = 0;
+        int NoGap=ui->Flags&LA_UI_FLAGS_NO_GAP;
+        int NoHeight=ui->Flags&LA_UI_FLAGS_UNDERNEATH;
+
+        //if (Fast && ui->C->B > B) {
+        //	//la_CalcUiItemInfluence(&uil->Colums, ui);
+        //	ui = ui->Item.pNext;
+        //	continue;
+        //}
+
+        if (!ui->Instructions){
+            if (ui->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->ExtraInstructions->Ptr);
+            if (ui->AT && ui->AT->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->AT->ExtraInstructions);
+            if (ui->PP.LastPs && ui->PP.LastPs->p->PropertyType == LA_PROP_OPERATOR){
+                laOperatorProp *ap = ui->PP.LastPs->p;
+                if (!ap->OperatorType) ap->OperatorType = laGetOperatorType(ap->OperatorID);
+                if (ap->OperatorType->ExtraInstructions) strMakeInstructions(&ui->Instructions, ap->OperatorType->ExtraInstructions);
+            }
+        }
+
+        if (/*!ui->NoRefresh && */ ui->PP.LastPs){
+            la_StepPropPack(&ui->PP);
+        }
+
+        la_UsePropPack(&ui->PP, 0);
+        //if (ui->PP.LastPs && (HyperValue = ui->PP.LastPs->p->Container ? ui->PP.LastPs->p->Container->Hyper : 0)){
+        //    laUseDataBlock(ui->PP.Go ? ui->PP.LastPs->UseInstance : ui->PP.RawThis->LastPs->UseInstance, ui->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, 0);
+        //}
+
+        if ((ui->AnimationDistinguish + 1) == ParentPanel->FrameDistinguish){
+            ParentPanel->Refresh |= LA_TAG_ANIMATION;
+            WaitAnimation = 1;
+        }
+        ui->AnimationDistinguish = ParentPanel->FrameDistinguish;
+
+        bt = (*ui->Type->Theme);
+
+        if (ui->Type == &_LA_UI_CONDITION){
+            laConditionUiExtraData *cued = ui->Extra;
+            la_StepExpression(cued->Expression);
+            cued->IsTrue = la_DoSingleExpression(cued->Expression);
+            if (!cued->IsTrue){
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_END){
+            ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){
+            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;
+            if (cued->IsTrue) ui = cued->EndUi;
+            else
+                ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){
+            laConditionUiExtraData *cued = ui->Extra;
+            ui->TL = ui->C->IL + bt->LP; ui->TR = ui->C->IR - bt->RP;
+            ui->TU = ui->C->B + bt->TP;  ui->TB = ui->TU+LA_RH;
+            if (!WaitAnimation){
+                ui->L = ui->TL; ui->R = ui->TR;
+                ui->U = ui->TU; ui->B = ui->TB;
+            }
+            if(!RowMode){
+                la_CalcUiItemInfluence(&uil->Columns, ui);
+            }else{
+                H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1;
+                la_AddRowNode(&ri, ui, bt, H*LA_RH);
+            }
+            if (ui->State == LA_UI_NORMAL){
+                cued->IsTrue = 0;
+                //if(cued->Remove && (ui->Item.pNext != cued->EndUi))
+                //	la_DestroyUiRange(uil, ui->Item.pNext, cued->ElseUi?cued->ElseUi->Item.pPrev:cued->EndUi->Item.pPrev);
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                cued->IsTrue = 1;
+                //if (cued->Remove && (ui->Item.pNext == cued->EndUi || ui->Item.pNext==cued->ElseUi)) {
+                //	la_CreateUiAfter(uil, ui, ui->Template, ui->PP.RawThis, ui->Page, uil->Columns.pFirst);
+                //}
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+
+        if (ui->Type == _LA_UI_ALIGN){
+            ui->TU = ui->C->B + bt->TP; ui->TB = ui->TU;
+            ui->TL = ui->C->IL; ui->TR = ui->C->IR;
+            if (ui->TB > Lowest) Lowest = ui->TB;
+            if (!WaitAnimation){
+                ui->L = ui->TL; ui->R = ui->TR;
+                ui->U = ui->TU; ui->B = ui->TB;
+            }
+            if(!RowMode){
+                la_CalcUiItemInfluence(&uil->Columns, ui);
+            }else{
+                ui->Flags|=LA_UI_FLAGS_TRANSPOSE;
+                H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1;
+                la_AddRowNode(&ri, ui, bt, H*LA_RH);
+            }
+            ui = ui->Item.pNext; continue;
+        }
+
+        if (ui->Type == &_LA_UI_ROW_BEGIN){
+            ui->TU = ui->C->B; ui->TL = ui->C->IL; ui->TR = ui->C->IR;
+            la_InitRowNode(&ri, ui, bt);
+            RowMode=1; ui=ui->Item.pNext; continue;
+        }
+
+        if (ui->Type == &_LA_UI_ROW_END){
+            la_CalculateRowExpand(&ri, ui, WaitAnimation);
+            la_CalcUiItemInfluence(&uil->Columns, ui);
+            RowMode=0; ui=ui->Item.pNext; continue;
+        }
+
+
+        if(!RowMode){ ui->TL = ui->C->IL + (NoGap?_PL:bt->LP); ui->TR = ui->C->IR - (NoGap?_PR:bt->RP); }
+
+        int GB=0;
+        if (ui->Type == _LA_UI_FIXED_GROUP && ui->Page->HeightCoeff < 0 && ui->Flags&LA_UI_FLAGS_PREFER_BOTTOM){ GB=ui->Page->TB-ui->Page->PanY; }
+
+        H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1;
+        ui->TU = ui->C->B + (NoGap?_PT:bt->TP);
+        if (H < 0){
+            if(B){ H = B + (H+1) * LA_RH - ui->TU; }
+            else{ H=LA_RH; }
+        } 
+        else H *= LA_RH;
+        ui->TB = ui->TU;
+        
+        int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+        if (ui->Type->ForType == LA_PROP_SUB && ui->PP.LastPs && ui->PP.LastPs->p && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB && ui->Type != _LA_UI_CANVAS){ //DynamicCreation
+            laPropIterator pi = {0}; laSubProp* uisp=ui->PP.LastPs->p;
+            if (ui->Type == _LA_UI_COLLECTION){
+                //void* TInstance = ui->PP.Go?laGetInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi):ui->PP.EndInstance;
+                void *TInstance = laGetInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi);
+                ui->PP.EndInstance = TInstance;
+                laUiList *iuil = ui->Subs.pFirst; 
+                laUiList *puil = iuil;
+                int Row = 0, Col = 0, RowPriority = ui->SymbolID > 0 ? 1 : 0, ElementLimit = ui->SymbolID ? abs(ui->SymbolID) : 0;
+                int Spread=ui->Expand>2?ui->Expand:0; if(Spread){ RowPriority=0; ElementLimit=0; }
+                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 ElementB = ui->TU;
+                real ElementWidth = ElementLimit ? 1.0f / ElementLimit : 1.0;
+                int MaxB = ElementB;
+                int CanGetTheme = laCanGetTheme(ui->PP.LastPs->p);laTheme* OriginalTheme=MAIN.CurrentTheme;
+                int CanGetGap= laCanGetGap(ui->PP.LastPs->p);
+                int Gap=0;
+
+                if (!ElementLimit) RowPriority = 0;
+
+                if (!TInstance){
+                    while (iuil){
+                        puil = iuil->Item.pNext;ui->PP.EndInstance=iuil->Instance; la_StopUsingPropPack(&ui->PP);
+                        la_DestroyTabPage(ui, iuil, 0);
+                        iuil = puil;
+                    }
+                }
+                while (TInstance){
+                    if(uisp->UiFilter && (!uisp->UiFilter(ui->PP.LastPs->UseInstance, TInstance))){
+                        TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi);
+                        Template = ui->Template?ui->Template:laGetPropertyUiDefine(&ui->PP, TInstance);
+                        ui->PP.EndInstance = TInstance; continue;
+                    }
+                    if(CanGetTheme){
+                        laTheme* t=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance);
+                        la_SwitchThemeQuick(t, OriginalTheme);
+                    }
+                    if(CanGetGap){
+                        int g=laGetUiGap(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance); g=g<0?0:g;
+                        Gap=g*LA_RH;
+                    }else Gap=0;
+
+                    if (ElementLimit){
+                        EL = tnsInterpolate(ui->TL, ui->TR, (Col)*ElementWidth);
+                        ER = tnsInterpolate(ui->TL, ui->TR, (Col + 1) * ElementWidth);
+                    }
+
+                    if (!iuil){
+                        la_AddInstancePage(ui, TInstance, 0);
+                        la_CalcUiTopInfluence(&uil->Columns, ui);
+                        if (Template) laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);
+                        SubB = la_UpdateUiListRecursive(ui->Page, Gap+Begin+(NoDecal?0:bt->TM), EL+(NoDecal?0:bt->LM), ER-(NoDecal?0:bt->RM), B, Fast, ParentPanel) + bt->TM;
+                        ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB;
+
+                        iuil = ui->Page->Item.pNext;
+                    }
+
+                    while (iuil && iuil->Instance != TInstance){
+                        while (iuil && iuil->Instance != TInstance){
+                            puil = iuil->Item.pNext;ui->PP.EndInstance=iuil->Instance; la_StopUsingPropPack(&ui->PP);
+                            la_DestroyTabPage(ui, iuil, 0);
+                            iuil = puil;
+                        }
+                        if (!iuil){
+                            la_AddInstancePage(ui, TInstance, 0);
+                            la_CalcUiTopInfluence(&uil->Columns, ui);
+                            if (Template) laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);
+                            SubB = la_UpdateUiListRecursive(ui->Page, Gap+Begin+(NoDecal?0:bt->TM), EL+(NoDecal?0:bt->LM), ER-(NoDecal?0:bt->RM), B, Fast, ParentPanel) + bt->TM;
+                            ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB;
+
+                            iuil = ui->Page->Item.pNext;
+                            break;
+                        }
+                    }
+
+                    if (iuil && iuil->Instance == TInstance){
+                        la_CalcUiTopInfluence(&uil->Columns, ui);
+                        SubB = la_UpdateUiListRecursive(iuil, Gap+Begin+(NoDecal?0:bt->TM), EL+(NoDecal?0:bt->LM), ER-(NoDecal?0:bt->RM), B, Fast, ParentPanel) + bt->TM;
+                        ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB;
+
+                        la_CalcUiItemInfluence(&uil->Columns, ui);
+                        iuil = iuil->Item.pNext;
+                        //TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi);
+                        //ui->PP.EndInstance = TInstance;
+                        if (!TInstance){
+                            while (iuil){
+                                puil = iuil->Item.pNext;ui->PP.EndInstance=iuil->Instance; la_StopUsingPropPack(&ui->PP);
+                                la_DestroyTabPage(ui, iuil, 0);
+                                iuil = puil;
+                            }
+                            break;
+                        }
+                        //continue;
+                    }
+                    TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi);
+                    Template = ui->Template?ui->Template:laGetPropertyUiDefine(&ui->PP, TInstance);
+                    ui->PP.EndInstance = TInstance;
+                    
+                    if(CanGetTheme){ la_SwitchThemeQuick(0, OriginalTheme); }
+
+                    if (RowPriority){
+                        Col += 1;
+                        if (Col >= ElementLimit){
+                            Col = 0;
+                            Row += 1;
+                            Begin = ElementB + bt->TM;
+                        }
+                    }elif(Spread){
+                        EL+=Spread*LA_RH;
+                        ER+=Spread*LA_RH;
+                    }else{
+                        Row += 1;
+                        Begin = ElementB + bt->TM;
+                        if (ElementLimit && Row >= ElementLimit){
+                            Row = 0;
+                            Col += 1;
+                            Begin = ui->TU + bt->TM;
+                        }
+                    }
+                    ui->TB = ElementB;
+                    MaxB = MaxB < ElementB ? ElementB : MaxB;
+                }
+                while (iuil){
+                    puil = iuil->Item.pNext;ui->PP.EndInstance=iuil->Instance; la_StopUsingPropPack(&ui->PP);
+                    la_DestroyTabPage(ui, iuil, 0);
+                    iuil = puil;
+                }
+                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 (!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){
+                void *TInstance = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance);
+                ui->PP.EndInstance = TInstance;
+                laUiTemplate *Template = ui->Template ? ui->Template : laGetPropertyUiDefine(&ui->PP, TInstance);
+                if(!Template) Template=laui_SubPropInfoDefault;
+                //ui->Template = Template;
+                if (!ui->Subs.pFirst && TInstance){
+                    la_AddInstancePage(ui, TInstance, 0);
+                    la_CalcUiTopInfluence(&uil->Columns, ui);
+                    laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);
+                    SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM), B, Fast, ParentPanel);
+                    ui->TB = SubB + bt->BM;
+                }else if (ui->Subs.pFirst){
+                    if (!TInstance || TInstance != ui->Page->Instance){ui->PP.EndInstance=((laUiList*)ui->Subs.pFirst)->Instance; la_StopUsingPropPack(&ui->PP);
+                        la_DestroyTabPage(ui, ui->Subs.pFirst, 0);
+                        ui->Page = 0;
+                        if (TInstance){
+                            la_AddInstancePage(ui, TInstance, 0);
+                            la_CalcUiTopInfluence(&uil->Columns, ui);
+                            laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext);
+                            SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM), B, Fast, ParentPanel);
+                            ui->TB = SubB + bt->BM;
+                        }else
+                            ui->TB = ui->TU + LA_RH + bt->BM;
+                    }else{
+                        SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM), B, Fast, ParentPanel);
+                        ui->TB = SubB + bt->BM;
+                    }
+                }
+                if (ui->TB-ui->TU<LA_RH) ui->TB = ui->TU + LA_RH;
+                if (!WaitAnimation){
+                    ui->L = ui->TL;
+                    ui->R = ui->TR;
+                    ui->U = ui->TU;
+                    ui->B = ui->TB;
+                }
+            }
+        }else{
+            if (ui->Type != _LA_UI_COLLECTION && (ui->Subs.pFirst || ui->Page) && ui->Type != _LA_UI_MENU_ROOT){
+                if (ui->Type != _LA_UI_CANVAS){
+                    int scrollw=ui->Page->ScrollerShownV?bt->RP*2+LA_SCROLL_W:0;
+                    la_CalcUiTopInfluence(&uil->Columns, ui);
+                    SubB = la_UpdateUiListRecursive(ui->Page,
+                        ui->TB + (ui->State == LA_UI_ACTIVE ? 0 : LA_RH)+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-scrollw, B, Fast, ParentPanel);
+                    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)){
+                        ui->Page->ScrollerShownH=!ui->Page->ScrollerShownH;
+                    }
+                    if(ui->Page->AllowScale){ui->Page->ScrollerShownH=1;}
+                    if(ui->Page->ScrollerShownH){subh-=LA_SCROLL_W-bt->BM;}
+                    if(GB && ui->TB >= GB){
+                        ui->Page->PanY=(SubB-ui->TB-bt->BM); if(ui->Page->PanY<0)ui->Page->PanY=0; }
+                    if(ui->Page->HeightCoeff){
+                        if((subh<ui->Page->TB-ui->Page->TU && (!ui->Page->ScrollerShownV)) ||
+                            (subh>=ui->Page->TB-ui->Page->TU && ui->Page->ScrollerShownV)){
+                            ui->Page->ScrollerShownV=!ui->Page->ScrollerShownV;
+                            ParentPanel->Refresh|=LA_TAG_RECALC_SCROLLER;
+                        }
+                        if(SubB-ui->Page->PanY<ui->TB-bt->BM-(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->BM:0)){
+                            ui->Page->PanY = (SubB-ui->TB-bt->BM+(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->BM:0));
+                            if(ui->Page->PanY<0){ui->Page->PanY=0;}
+                            //ParentPanel->Refresh|=LA_TAG_RECALC_SCROLLER;
+                        }
+                    }
+                    if(ui->Page->ScrollerShownH && !ui->Page->HeightCoeff){
+                        ui->TB+=(bt->BP*2+LA_SCROLL_W); }
+                }else{
+                    laUiList *suil;
+                    if(!MAIN.CurrentWindow->MaximizedUi || ui!=MAIN.CurrentWindow->MaximizedUi){
+                        la_CalcUiTopInfluence(&uil->Columns, ui);
+                        for (suil = ui->Subs.pFirst; suil; suil = suil->Item.pNext){
+                            SubB = la_UpdateUiListRecursive(suil, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM), ui->TU+H, Fast, ParentPanel);
+                        }
+                    }
+                    ui->TB = ui->TU + H;
+                }
+            }else ui->TB = ui->TU + H;
+        }
+
+        if (ui->TB > Lowest) Lowest = ui->TB + (bt ? (NoGap?_PB:bt->BP) : 0);
+        if(!RowMode){
+            if(!NoHeight) la_CalcUiItemInfluence(&uil->Columns, ui);
+        }else{
+            la_AddRowNode(&ri, ui, bt, H);
+        }
+
+        if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; }
+
+        if(ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocketRuntimePosition(ui); }
+
+        ui = ui->Item.pNext;
+    }
+
+    uil->TR=MaxR>uil->TR?MaxR:uil->TR;
+
+    if (uil->Columns.pFirst) uil->TB = ((laColumn *)uil->Columns.pFirst)->B;
+    else uil->TB = Lowest;
+
+    if (!WaitAnimation){
+        uil->L = uil->TL;
+        uil->R = uil->TR;
+        uil->U = uil->TU;
+        uil->B = uil->TB;
+    }
+
+    MAIN.UiScale=uil->SaveScale;
+    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;
+    return uil->TB;
+}
+int la_AnimateSingleUiSize(int To, int *Now){
+    int Delta;
+
+    if (To != *Now){
+        Delta = (To - (*Now)) * (MAIN.AnimationSpeed) * MAIN.LastFrameTime * 60;
+        if (!Delta) Delta = To > (*Now) ? 1 : -1;
+        *Now += Delta;
+        return 1;
+    }else
+        return 0;
+}
+int la_AnimateUiListRecursive(laUiList *uil){
+    laUiItem *ui;
+    int Again = 0;
+    for (ui = uil->UiItems.pFirst; ui; ui = ui->Item.pNext){
+        int TB = ui->B, TU = ui->U, TL = ui->L, TR = ui->R, SB, SU, SL, SR;
+
+        Again += (la_AnimateSingleUiSize(ui->TB, &ui->B) +
+                  la_AnimateSingleUiSize(ui->TU, &ui->U) +
+                  la_AnimateSingleUiSize(ui->TL, &ui->L) +
+                  la_AnimateSingleUiSize(ui->TR, &ui->R));
+
+        if (ui->Type == _LA_UI_COLLECTION_SELECTOR || ui->Type == _LA_UI_COLLECTION_SINGLE ||
+            (ui->PP.LastPs && ui->PP.LastPs->p && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB && ui->Type != _LA_UI_CANVAS)){
+            laUiList *suil;
+            for (suil = ui->Subs.pFirst; suil; suil = suil->Item.pNext){
+                Again += la_AnimateUiListRecursive(suil);
+            }
+        }else if (ui->Type != _LA_UI_COLLECTION && ui->Type != &_LA_UI_ROW_END &&
+                 (ui->Subs.pFirst || ui->Page) && ui->Type != _LA_UI_MENU_ROOT){
+            Again += la_AnimateUiListRecursive(ui->Page);
+        }
+    }
+    Again += (la_AnimateSingleUiSize(uil->TB, &uil->B) +
+              la_AnimateSingleUiSize(uil->TU, &uil->U) +
+              la_AnimateSingleUiSize(uil->TL, &uil->L) +
+              la_AnimateSingleUiSize(uil->TR, &uil->R));
+
+    return Again;
+}
+int la_DrawUiItem(laUiItem *ui){
+    tnsUseNoTexture();
+    tnsColor4d(1, 1, 1, 1);
+    tnsVertex2d(ui->L, ui->U);
+    tnsVertex2d(ui->R, ui->U);
+    tnsVertex2d(ui->R, ui->B);
+    tnsVertex2d(ui->L, ui->B);
+    tnsPackAs(GL_LINE_LOOP);
+}
+int la_DrawActiveUiItemOverlay(laUiItem *ui){
+    tnsUseNoTexture();
+    tnsColor4d(1, 1, 1, 1);
+    tnsVertex2d(ui->L - 1, ui->U - 1);
+    tnsVertex2d(ui->R + 1, ui->U - 1);
+    tnsVertex2d(ui->R + 1, ui->B + 1);
+    tnsVertex2d(ui->L - 1, ui->B + 1);
+    tnsPackAs(GL_LINE_LOOP);
+}
+int la_UiInBound(laUiItem *ui, int L, int R, int U, int B){
+    if (ui->R <= L || ui->L >= R || ui->U >= B || ui->B <= U) return 0;
+    return 1;
+}
+int la_UiInBoundEx(laUiItem *ui, laUiListDraw *uild){
+    laUiListDrawItem *uildi = uild->Items.pFirst;
+    laUiList *Target = uildi->Target;
+    int L, R, U, B;
+
+    if (!Target) return la_UiInBound(ui, uildi->L, uildi->R, uildi->U, uildi->B);
+
+    L = Target->L + Target->PanX + uildi->DifX;
+    R = Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L);
+    B = Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U);
+    U = Target->U + Target->PanY + uildi->DifY;
+
+    return la_UiInBound(ui, L, R, U, B);
+}
+int la_UiListInBoundEx(laUiList *uil, laUiListDraw *uild){
+    laUiListDrawItem *uildi = uild->Items.pFirst;
+    laUiList *Target = uildi->Target;
+    int L, R, U, B;
+
+    if (Target){
+        L = Target->L + Target->PanX + uildi->DifX;
+        R = Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L);
+        B = Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U);
+        U = Target->U + Target->PanY + uildi->DifY;
+        if (uil->R <= L || uil->L >= R || uil->U >= B || uil->B <= U) return 0;
+        return 1;
+    }else{
+        if (uil->R <= uildi->L || uil->L >= uildi->R || uil->U >= uildi->B || uil->B <= uildi->U) return 0;
+        return 1;
+    }
+}
+
+laUiItem *la_FindUiWithMark(laUiList *uil, char *mark){
+    laUiItem *ui = uil->UiItems.pFirst;
+    while (!strGetArgument(ui->Instructions, mark))
+        ui = ui->Item.pNext;
+    return ui;
+}
+laUiList *la_FindSubListWithInstance(laUiItem *ui, void *Instance){
+    laUiList *uil;
+    for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){
+        if (uil->Instance == Instance) return uil;
+    }
+    return uil;
+}
+
+void la_DrawUiListArrows(laUiList *uil, int L, int R, int U, int B, real* color){
+    int mx=(L+R)/2; int my=(U+B)/2;
+    if(uil->R-uil->PanX>R){ tnsDrawStringAuto("▷", color, R-LA_RH, R, my-LA_RH2, LA_TEXT_ALIGN_RIGHT); }
+    if(uil->L-uil->PanX<L){ tnsDrawStringAuto("◁", color, L, L+LA_RH, my-LA_RH2, LA_TEXT_ALIGN_LEFT); }
+    if(uil->U-uil->PanY<U){ tnsDrawStringAuto("△", color, mx-LA_RH2, mx+LA_RH2, U, LA_TEXT_ALIGN_CENTER); }
+    if(uil->B-uil->PanY>B){ tnsDrawStringAuto("▽", color, mx-LA_RH2, mx+LA_RH2, B-LA_RH, LA_TEXT_ALIGN_CENTER); }
+    tnsFlush();
+}
+void la_DrawUiListScrollerV(laUiList *uil, int DisplayOffset, int TotalH, int DisplayH, int UiR){
+    if(!uil->ScrollerShownV) return;
+    
+    int W = LA_SCROLL_W;
+    int Len = (int)((real)DisplayH / (real)TotalH * (real)DisplayH);
+    int Offset = (int)((real)DisplayOffset / (real)TotalH * (real)DisplayH);
+    int U = uil->U + Offset;
+    int B = U + Len;
+    int L = UiR - _LA_THEME_PANEL->RM - W;
+    int R = L + W;
+
+    if (B > U + DisplayH) B = U + DisplayH;
+    if (U < uil->U) U = uil->U;
+
+    if (B <= uil->U || U >= uil->B) return;
+
+    if (B > uil->U + DisplayH) B = uil->U + DisplayH;
+    if (U < uil->U) U = uil->U;
+
+    tnsUseNoTexture();
+
+    laBoxedTheme* bt=_LA_THEME_PANEL;
+    real* color=laThemeColor(bt, LA_BT_TEXT);
+    tnsColor4d(LA_COLOR3(color), 0.8);
+    tnsVertex2d(R, U);
+    tnsVertex2d(L, U);
+    tnsVertex2d(L, B);
+    tnsVertex2d(R, B);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    tnsColor4d(LA_COLOR3(color), 0.8);
+    tnsVertex2d(R, uil->U);
+    tnsVertex2d(L, uil->U);
+    tnsVertex2d(L, uil->U + DisplayH);
+    tnsVertex2d(R, uil->U + DisplayH);
+    tnsPackAs(GL_LINE_LOOP);
+
+    int HU=(U+B)/2+LA_RH2;
+    tnsDrawStringAuto("☰",laThemeColor(bt, LA_BT_BORDER),L-100,R+100,HU,LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER);
+}
+void la_DrawUiListScrollerH(laUiList *uil, int DisplayOffset, int TotalW, int DisplayW, int UiB){
+    if(!uil->ScrollerShownH) return;
+    
+    int W = LA_SCROLL_W;
+    int Len = (int)((real)DisplayW / (real)TotalW * (real)DisplayW);
+    int Offset = (int)((real)DisplayOffset / (real)TotalW * (real)DisplayW);
+    int L = uil->L + Offset;
+    int R = L + Len;
+    int U = UiB - _LA_THEME_PANEL->RM - W;
+    int B = U + W;
+
+    if (B > U + DisplayW) B = U + DisplayW;
+    if (U < uil->U) U = uil->U;
+
+    if (R <= uil->L || L >= uil->R) return;
+
+    if (R > uil->L + DisplayW) R = uil->L + DisplayW;
+    if (L < uil->L) L = uil->L;
+
+    tnsUseNoTexture();
+
+    laBoxedTheme* bt=_LA_THEME_PANEL;
+    real* color=laThemeColor(bt, LA_BT_TEXT);
+    tnsColor4d(LA_COLOR3(color), 0.8);
+    tnsVertex2d(R, U);
+    tnsVertex2d(L, U);
+    tnsVertex2d(L, B);
+    tnsVertex2d(R, B);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    tnsColor4d(LA_COLOR3(color), 0.8);
+    tnsVertex2d(uil->L,U);
+    tnsVertex2d(uil->L,B);
+    tnsVertex2d(uil->L + DisplayW,B);
+    tnsVertex2d(uil->L + DisplayW,U);
+    tnsPackAs(GL_LINE_LOOP);
+
+    int HU=(U+B)/2+LA_RH2;
+    tnsDrawStringAuto("↔",laThemeColor(bt, LA_BT_BORDER),L-100,R+100,HU,LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER);
+}
+void la_DrawInstanceBkg(laUiList *uil, real* color){
+    tnsUseNoTexture();
+    tnsColor4dv(color);
+    tnsVertex2d(uil->L, uil->U); tnsVertex2d(uil->R, uil->U);
+    tnsVertex2d(uil->R, uil->B); tnsVertex2d(uil->L, uil->B);
+    tnsPackAs(GL_TRIANGLE_FAN);
+}
+void la_InitSocketRecord(laUiListDraw* uild, laUiList* container){
+    laSocketRecord* sr;
+    while(sr=lstPopItem(&uild->SocketRecord)){ memFree(sr); }
+    uild->WiresContainer=container;
+}
+void la_GetUiListOffsetUntil(laUiListDraw* uild, int* X, int* Y){
+    *X=*Y=0; for(laUiListDrawItem* lip=uild->Items.pLast;lip&&lip->Target;lip=lip->Item.pPrev){
+        if(lip->Target==uild->WiresContainer) break;
+        laUiList* uil=lip->Target; *X+=uil->PanX; *Y+=uil->PanY;
+    }
+}
+void la_RecordSocket(laUiListDraw* uild, laUiList* uil, laUiItem* ui){
+    laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);
+    int PanX, PanY;
+    if(pc==LA_PC_SOCKET_OUT){
+        laNodeOutSocket* s=ui->PP.EndInstance;
+        la_GetUiListOffsetUntil(uild, &s->RuntimePX, &s->RuntimePY); 
+    }else{
+        laNodeInSocket* s=ui->PP.EndInstance; if(!s->Source) return;
+        laSocketRecord* sr=memAcquireSimple(sizeof(laSocketRecord));
+        sr->In=s; sr->Out=s->Source; lstAppendItem(&uild->SocketRecord, sr);
+    }
+}
+void la_RegenerateWireColors(){
+    if(MAIN.WireColorCache) free(MAIN.WireColorCache);
+    laTheme* t=MAIN.CurrentTheme;
+    MAIN.WireColorCache = calloc(1, sizeof(real)*4*MAIN.WireColorSlices);
+    real hcy[]={0.0,0.8,0.6}; hcy[1]=t->WireSaturation; hcy[2]=t->WireBrightness;
+    for(int i=0;i<MAIN.WireColorSlices;i++){
+        hcy[0]=(real)i/(real)MAIN.WireColorSlices;
+        tnsHCYtoRGB(hcy, &MAIN.WireColorCache[i*4]); MAIN.WireColorCache[i*4+3]=t->WireTransparency;
+    }
+}
+void la_SendWireVerts(real x1, real y1, real x2, real y2, real circle_r){
+    tnsVector2d v1,vi,v2,v1s,v2s; real dist=0;
+    v1[0]=x1; v1[1]=y1; v2[0]=x2; v2[1]=y2;
+    tnsInterpolate2dv(v1,v2,0.5,vi);
+    if(MAIN.WireSaggyness>0.01){ dist=tnsDist2dv(v1,v2); vi[1]+=log(dist+1)*MAIN.WireSaggyness; }
+    tnsVectorMinus2d(v1s,vi,v1); tnsNormalizeSelf2d(v1s); tnsVectorMultiSelf2d(v1s,circle_r);
+    tnsVectorMinus2d(v2s,vi,v2); tnsNormalizeSelf2d(v2s); tnsVectorMultiSelf2d(v2s,circle_r);
+    tnsVectorAccum2d(v1, v1s); tnsVectorAccum2d(v2, v2s);
+
+    if(MAIN.WireSaggyness<0.01){ tnsVertex2d(v1[0],v1[1]); tnsVertex2d(v2[0],v2[1]); return; }
+
+    int seglen=3, steps=dist/seglen+1; real step=1.0f/steps;
+    tnsVertex2d(v1[0],v1[1]);
+    for(int i=1;i<=steps;i++){
+        real ratio=i==steps?1.0f:step*i;
+        tnsInterpolateTripple2d(v1,vi,v2,ratio, v1s);
+        tnsVertex2d(v1s[0],v1s[1]);
+    }
+}
+void la_DrawNodeWires(laUiListDraw* uild){
+    if(!uild->SocketRecord.pFirst && !MAIN.tNodeIn.Source){ return; }
+    laBoxedTheme* bt=_LA_THEME_SOCKET;
+
+    tnsUseNoTexture();
+#define _RSLICES 16
+    real v[_RSLICES*4]; int idx[_RSLICES*2+2]; real r=LA_RH2/TNS_MAX2(uild->WiresContainer->Scale,1);
+    for(laSocketRecord*sr=uild->SocketRecord.pFirst;sr;sr=sr->Item.pNext){
+        int cid=sr->In->ColorId%MAIN.WireColorSlices*4;
+
+        int inx=sr->In->RuntimeX+sr->In->RuntimePX, iny=sr->In->RuntimeY+sr->In->RuntimePY;
+        int outx=sr->Out->RuntimeX+sr->Out->RuntimePX, outy=sr->Out->RuntimeY+sr->Out->RuntimePY;
+        if(sr->Out==&MAIN.tNodeOut){ outx=inx+MAIN.tNodeOut.RuntimeX+MAIN.tNodeOut.RuntimePX; outy=iny+MAIN.tNodeOut.RuntimeY+MAIN.tNodeOut.RuntimePY; }
+
+        tnsMakeRing2d(v,idx,_RSLICES, inx, iny, r, r*0.6);
+        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);
+        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);
+
+        tnsMakeRing2d(v,idx,_RSLICES, outx, outy, r, r*0.6);
+        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);
+        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);
+    }
+    if(MAIN.tNodeIn.Source){
+        laNodeInSocket* ins=&MAIN.tNodeIn; laNodeOutSocket* outs=ins->Source;
+        int cid=ins->ColorId%MAIN.WireColorSlices*4;
+
+        int outx=outs->RuntimeX+outs->RuntimePX, outy=outs->RuntimeY+outs->RuntimePY;
+        int inx=ins->RuntimeX+ins->RuntimePX+outx, iny=ins->RuntimeY+ins->RuntimePY+outy;
+
+        tnsMakeRing2d(v,idx,_RSLICES, inx, iny, r, r*0.6);
+        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);
+        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);
+
+        tnsMakeRing2d(v,idx,_RSLICES, outx, outy, r, r*0.6);
+        tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2);
+        tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP);
+    }
+#undef _RSLICES
+    tnsFlush();
+
+    int ww=MAIN.WireThickness*TNS_MIN2(uild->WiresContainer->Scale,1);
+    glLineWidth(ww);
+    for(laSocketRecord*sr=uild->SocketRecord.pFirst;sr;sr=sr->Item.pNext){
+        int cid=sr->In->ColorId%MAIN.WireColorSlices*4;
+        int inx=sr->In->RuntimeX+sr->In->RuntimePX, iny=sr->In->RuntimeY+sr->In->RuntimePY;
+        int outx=sr->Out->RuntimeX+sr->Out->RuntimePX, outy=sr->Out->RuntimeY+sr->Out->RuntimePY;
+        if(sr->Out==&MAIN.tNodeOut){ outx=inx+MAIN.tNodeOut.RuntimeX+MAIN.tNodeOut.RuntimePX; outy=iny+MAIN.tNodeOut.RuntimeY+MAIN.tNodeOut.RuntimePY; }
+
+        la_SendWireVerts(inx, iny, outx, outy, r*0.9);
+        tnsColor4dv(&MAIN.WireColorCache[cid]); tnsPackAs(GL_LINE_STRIP);
+    }
+    if(MAIN.tNodeIn.Source){
+        laNodeInSocket* ins=&MAIN.tNodeIn; laNodeOutSocket* outs=ins->Source;
+        int cid=ins->ColorId%MAIN.WireColorSlices*4;
+
+        int outx=outs->RuntimeX+outs->RuntimePX, outy=outs->RuntimeY+outs->RuntimePY;
+        int inx=ins->RuntimeX+ins->RuntimePX+outx, iny=ins->RuntimeY+ins->RuntimePY+outy;
+        
+        la_SendWireVerts(inx, iny, outx, outy, r*0.9);
+        tnsColor4dv(&MAIN.WireColorCache[cid]); tnsPackAs(GL_LINE_STRIP);
+    }
+    tnsFlush();
+    glLineWidth(1);
+
+    la_InitSocketRecord(uild,0);
+}
+void la_SwitchThemeQuick(laTheme* t, laTheme* DefaultTheme){
+    if(!DefaultTheme){return;} MAIN.CurrentTheme = t?t:DefaultTheme; t=MAIN.CurrentTheme;
+    for(laBoxedTheme* bt = t->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){ (*bt->BackRef) = bt; }
+}
+int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int U, int B, int LimH, int ConditionStackLevel, int GlobalX, int GlobalY, int RegisterNodes){
+    laUiItem *ui;
+    laBoxedTheme *bt;
+    laUiList *sub;
+    laUiListDrawItem *uildi;
+    int Ret = 0;
+
+    if (!uil) return;
+
+    //printf("d %d\n",MAIN.CurrentPanel->FrameDistinguish);
+
+    ui = uil->UiItems.pFirst;
+    if(uil->PanY<0){uil->PanY=0;}
+    if (!la_SetUpUiListMatrix(uild, uil, L, R, LimH, B - U, GlobalX, GlobalY)) return 0;
+
+    uil->SaveScale=MAIN.UiScale;
+    MAIN.UiScale*=uil->Scale;
+    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;
+
+    for (; ui;){
+
+        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;
+
+        if (ui->Type == &_LA_UI_CONDITION){
+            laConditionUiExtraData *cued = ui->Extra;
+            la_StepExpression(cued->Expression);
+            cued->IsTrue = la_DoSingleExpression(cued->Expression);
+            if (!cued->IsTrue){
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_END){
+            ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){
+            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;
+            if (cued->IsTrue) ui = cued->EndUi;
+            else
+                ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){
+            laConditionUiExtraData *cued = ui->Extra;
+            ui->Type->Draw(ui, LA_RH);
+            if (ui->State == LA_UI_NORMAL){
+                cued->IsTrue = 0;
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                cued->IsTrue = 1;
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+
+        if (ui->AnimationDistinguish != MAIN.CurrentPanel->FrameDistinguish) Ret = 1;
+
+        int NeedDraw=0;
+        if (la_UiInBoundEx(ui, uild)){ NeedDraw=1; }
+
+        if(NeedDraw){
+            if (!ui->Type->Draw){ la_DrawUiItem(ui); tnsFlush();
+            }else{ ui->Type->Draw(ui, LA_RH); }
+
+            if (ui->Type->Tag & LA_UI_TAG_IS_OFFSCREEN){
+                tnsFlush();
+                tnsDrawToOffscreen(MAIN.CurrentPanel->OffScr, 1, 0);
+                tnsResetViewMatrix();
+            }
+
+            if (ui->Type->Tag & (LA_UI_TAG_NEED_REBUILD)){
+                la_RebuildCurrentUiListMatrix(uild, uil, LimH, B - U);
+                if (ui->CanvasTemplate->SecondDraw) ui->CanvasTemplate->SecondDraw(ui, LA_RH);
+                tnsFlush();
+            }
+        }
+
+        if(NeedDraw || RegisterNodes){
+            if (RegisterNodes && ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocket(uild,uil,ui); }
+
+            if (ui->Type == _LA_UI_FIXED_GROUP ||
+                ui->Type == _LA_UI_TAB ||
+                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;
+                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,
+                    (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);
+                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);
+                int CanGetTheme = laCanGetTheme(ui->PP.LastPs->p);laTheme* OriginalTheme=MAIN.CurrentTheme;
+                void *Active = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance);
+                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                    int State;
+                    ui->PP.EndInstance = sub->Instance;
+
+                    if ((!la_UiListInBoundEx(sub, uild)) && (!RegisterNodes)) continue;
+
+                    if(!(ui->Flags&LA_UI_COLLECTION_NO_HIGHLIGHT) && NeedDraw){
+                        if (CanGetState){
+                            State = laGetUiState(ui->PP.LastPs->p, sub->Instance);
+                            la_DrawInstanceBkg(sub, laAccentColor(LA_BT_NORMAL));
+                        }elif (sub->Instance == Active){
+                            la_DrawInstanceBkg(sub, laAccentColor(LA_BT_NORMAL));
+                        }
+                    }
+
+                    if(CanGetTheme){
+                        laTheme* t=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance);
+                        la_SwitchThemeQuick(t, OriginalTheme);
+                        if(t) la_DrawInstanceBkg(sub, laThemeColor(_LA_THEME_FLOATING_PANEL ,LA_BT_NORMAL));
+                    }
+
+                    tnsFlush();
+                    Ret += la_DrawUiListRecursive(uild, sub, L, R, U, B, 10000, ConditionStackLevel, GlobalX, GlobalY, RegisterNodes);
+                    
+                    if(CanGetTheme){ la_SwitchThemeQuick(0, OriginalTheme); }
+                }
+                ui->PP.EndInstance = Active;
+            }elif (ui->Type == _LA_UI_CANVAS){
+                if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){
+                    for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                        tnsFlush();
+                        Ret += la_DrawUiListRecursive(uild, sub, L, R, U, B, 10000, ConditionStackLevel, GlobalX, GlobalY, RegisterNodes);
+                    }
+                }
+            }
+            ui = ui->Item.pNext;
+        }else{
+            ui = ui->Item.pNext;
+        }
+    }
+    tnsFlush();
+
+    if(uild->WiresContainer == uil){ la_DrawNodeWires(uild); }
+
+    la_RestoreLastUiListMatrix(uild, B - U);
+
+    MAIN.UiScale=uil->SaveScale;
+    MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale;
+    return Ret;
+}
+int la_DrawPanelScrollBarV(int L, int R, int U, int B, real Total, real Range, real Offset){
+    int Begin = U + (int)(Offset / Total * (real)(B - U)) + 3;
+    int End = Begin + (int)(Range / Total * (real)(B - U)) - 3;
+    tnsUseNoTexture();
+    tnsColor4d(1, 1, 1, 1);
+    tnsVertex2d(L, U);
+    tnsVertex2d(R, U);
+    tnsVertex2d(R, B);
+    tnsVertex2d(L, B);
+    tnsPackAs(GL_LINE_LOOP);
+    tnsVertex2d(L + 3, Begin);
+    tnsVertex2d(R - 3, Begin);
+    tnsVertex2d(R - 3, End);
+    tnsVertex2d(L + 3, End);
+    tnsPackAs(GL_LINE_LOOP);
+}
+int laIsInUiItem(laUiItem *ui, int x, int y){
+    if (x < ui->L || x > ui->R || y < ui->U || y > ui->B) return 0;
+    return 1;
+}
+int laIsInBound(int x, int y, int l, int r, int u, int b){
+    if (x < l || x > r || y < u || y > b) return 0;
+    return 1;
+}
+laColumn *la_DetectSplit(laColumn *Root, int LocalX);
+laUiItem *la_DetectUiItemRecursive(laUiList *uil, int x, int y, int LimB, laListHandle *LocalBuf, int Deep){
+    laUiItem *ui, *tui;
+    laBoxedTheme *bt;
+    laUiList *sub;
+    int CPB = 0;
+
+    if (!uil || (LimB && y > LimB)) return 0;
+
+    x += uil->PanX;
+    y += uil->PanY;
+
+    for (ui = uil->UiItems.pFirst; ui;){
+
+        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;
+
+        if (ui->Type == &_LA_UI_CONDITION){
+            laConditionUiExtraData *cued = ui->Extra;
+            //la_StepExpression(cued->Expression); for some reason we can't step here, only step in update :thinking:
+            cued->IsTrue = la_DoSingleExpression(cued->Expression);
+            if (!cued->IsTrue){
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_END){
+            ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){
+            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;
+            if (cued->IsTrue) ui = cued->EndUi;
+            else
+                ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){
+            laConditionUiExtraData *cued = ui->Extra;
+            if (laIsInUiItem(ui, x, y)){
+                lstAppendPointer(LocalBuf, uil);
+                return ui;
+            }
+            if (ui->State == LA_UI_NORMAL){
+                cued->IsTrue = 0;
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                cued->IsTrue = 1;
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+
+        //printf("%s > ",ui->Type->Identifier?ui->Type->Identifier:"-");
+
+        if (ui->Type != _LA_UI_COLLECTION && ui->Type != _LA_UI_FIXED_GROUP && ui->Type != _LA_UI_TAB && ui->Type != _LA_UI_CANVAS && laIsInUiItem(ui, x, y)){
+            int Add=1; if(ui->Type==_LA_UI_COLUMN_ADJUSTER){
+                if(!la_DetectSplit(ui->C, x)) Add=0;
+            }
+            if(Add){ lstAppendPointer(LocalBuf, uil); return ui; }
+        }
+
+        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){
+            if (ui->Page->HeightCoeff) CPB = ui->B;
+            else CPB = ui->Page->B;
+            if (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){
+                if (tui = la_DetectUiItemRecursive(ui->Page, x /* + ui->Page->PanX*/, y /*+ ui->Page->PanY*/, CPB, LocalBuf, Deep)){
+                    lstAppendPointer(LocalBuf, uil);
+                    return tui;
+                }
+            }else if (laIsInUiItem(ui, x, y)){
+                lstAppendPointer(LocalBuf, uil);return ui;
+            }
+        }
+        if (ui->Type == _LA_UI_COLLECTION){
+            if (laIsInUiItem(ui, x, y)){
+                lstAppendPointer(LocalBuf, uil);
+                if (ui->Subs.pFirst) ((laUiList *)ui->Subs.pFirst)->HeightCoeff = LimB;
+                if(Deep){
+                    for(laUiList* iuil=ui->Subs.pFirst;iuil;iuil=iuil->Item.pNext){
+                        if (laIsInBound(x, y, iuil->L, iuil->R, iuil->U, iuil->B)){
+                            if (tui = la_DetectUiItemRecursive(iuil, x , y , iuil->B, LocalBuf, Deep)){
+                                lstAppendPointer(LocalBuf, iuil);
+                                return tui;
+                            }
+                        }
+                    }
+                }
+                return ui;
+            }
+        }
+        if (ui->Type == _LA_UI_CANVAS){
+            if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){
+                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                    if (tui = la_DetectUiItemRecursive(sub, x, y, ui->B, LocalBuf, Deep)){
+                        lstAppendPointer(LocalBuf, uil);
+                        return tui;
+                    }
+                }
+            }
+            if (laIsInUiItem(ui, x, y)){
+                lstAppendPointer(LocalBuf, uil);
+                return ui;
+            }
+        }
+
+        ui = ui->Item.pNext;
+    }
+    return 0;
+}
+laUiItem *la_DetectSocketRecursive(laUiList* uil, int x, int y, int LimB, laPropContainer* PCInOrOut){
+    laListHandle Locals={0};
+    laUiItem* ui=la_DetectUiItemRecursive(uil, x,y,LimB,&Locals, 1);
+    while(lstPopPointer(&Locals));
+    //printf("%s\n", ui?ui->Type->Identifier:"?");
+    if(ui && ui->Type==_LA_UI_NODE_SOCKET){
+        laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);
+        if(pc==PCInOrOut) return ui;
+    }
+    return 0;
+}
+laUiList *la_DetectUiListRecursive(laUiList *uil, int x, int y, int LimH,
+                                   laUiItem **ParentUi, laUiList **ScrollUil, laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception){
+    laUiItem *ui = uil->UiItems.pFirst;
+    laBoxedTheme *bt;
+    laUiList *tuil;
+    laUiList *sub;
+    int CPB = 0;
+
+    x += uil->PanX;
+    y += uil->PanY;
+
+    if (y > LimH) return uil;
+
+    if (/*uil->ScrollerShownV && */ laIsInBound(x, y, uil->R, uil->R+LA_SCROLL_W+4, uil->U, uil->B) ||
+        /*uil->ScrollerShownH && */ laIsInBound(x, y, uil->L, uil->R, uil->B, uil->B+LA_SCROLL_W+4)){
+        if (ScrollUil) *ScrollUil = uil; /* if (ParentUi)*ParentUi = uil;*/
+        return uil;
+    }
+
+    for (ui = uil->UiItems.pFirst; ui;){
+
+        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;
+
+        if (ui->Type == &_LA_UI_CONDITION){
+            laConditionUiExtraData *cued = ui->Extra;
+            //la_StepExpression(cued->Expression);
+            cued->IsTrue = la_DoSingleExpression(cued->Expression);
+            if (!cued->IsTrue){
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+        if (ui->Type == &_LA_UI_CONDITION_END){
+            ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){
+            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;
+            if (cued->IsTrue) ui = cued->EndUi;
+            else
+                ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){
+            laConditionUiExtraData *cued = ui->Extra;
+            if (ui->State == LA_UI_NORMAL){
+                cued->IsTrue = 0;
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                cued->IsTrue = 1;
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+
+        if (InToContainerUI && ui != Exception){
+            if (ui->Type == _LA_UI_CANVAS && !(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){
+                if (ContainerParent) (*ContainerParent) = uil;
+                if (ParentUi) *ParentUi = ui;
+                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                    //if (y > LimH) return uil;
+                    if (laIsInBound(x, y, sub->L, sub->R, sub->U, sub->B) && (tuil = la_DetectUiListRecursive(sub, x, y, ui->B, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception))){
+                        return tuil;
+                    }
+                }
+            }
+        }
+
+        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){
+            if (ui->Page->HeightCoeff) CPB = ui->B;
+            else CPB = ui->Page->B;
+            if (ui->Page->ScrollerShownV && laIsInBound(x, y, ui->R - LA_SCROLL_W - bt->RP*2, ui->R, ui->Page->U, CPB)){
+                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui;
+            }elif (ui->Page->ScrollerShownH && laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->B - LA_SCROLL_W - bt->BP*2, ui->B)){
+                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui;
+            }elif (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){
+                if (ParentUi) *ParentUi = ui; 
+                if (tuil = la_DetectUiListRecursive(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception)) return tuil;
+            }
+        }
+
+        ui = ui->Item.pNext;
+    }
+    return uil;
+}
+laUiList *la_DetectUiListRecursiveDeep(laUiList *uil, int x, int y, int LimH, laUiItem **ParentUi, laUiList **ScrollUil,
+                                       laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception, laListHandle* levels){
+    laUiItem *ui = uil->UiItems.pFirst;
+    laBoxedTheme *bt;
+    laUiList *tuil;
+    laUiList *sub;
+    int CPB = 0;
+
+    laUiListRecord* uilr=lstAppendPointerSized(levels, uil, sizeof(laUiListRecord));
+
+    x += uil->PanX;
+    y += uil->PanY;
+
+    if (y > LimH) return uil;
+    
+    if (/*uil->ScrollerShownV && */ laIsInBound(x, y, uil->R, uil->R+LA_SCROLL_W+4, uil->U, uil->B) ||
+        /*uil->ScrollerShownH && */ laIsInBound(x, y, uil->L, uil->R, uil->B, uil->B+LA_SCROLL_W+4)){
+        if (ScrollUil) *ScrollUil = uil; /* if (ParentUi)*ParentUi = uil;*/
+        return uil;
+    }
+
+    for (ui = uil->UiItems.pFirst; ui;){
+
+        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;
+
+        if (ui->Type == &_LA_UI_CONDITION){
+            laConditionUiExtraData *cued = ui->Extra;
+            //la_StepExpression(cued->Expression);
+            cued->IsTrue = la_DoSingleExpression(cued->Expression);
+            if (!cued->IsTrue){
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+        if (ui->Type == &_LA_UI_CONDITION_END){
+            ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == &_LA_UI_CONDITION_ELSE){
+            laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra;
+            if (cued->IsTrue) ui = cued->EndUi;
+            else
+                ui = ui->Item.pNext;
+            continue;
+        }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){
+            laConditionUiExtraData *cued = ui->Extra;
+            if (ui->State == LA_UI_NORMAL){
+                cued->IsTrue = 0;
+                ui = cued->ElseUi ? cued->ElseUi : cued->EndUi;
+            }else{
+                cued->IsTrue = 1;
+                ui = ui->Item.pNext;
+            }
+            continue;
+        }
+
+        if (InToContainerUI && ui != Exception){
+            if (ui->Type == _LA_UI_CANVAS && !(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){
+                if (ContainerParent) (*ContainerParent) = uil;
+                if (ParentUi) *ParentUi = ui; uilr->pui=ui;
+                for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                    //if (y > LimH) return uil;
+                    if (laIsInBound(x, y, sub->L, sub->R, sub->U, sub->B) && (tuil = la_DetectUiListRecursiveDeep(sub, x, y, ui->B, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels))){
+                        return tuil;
+                    }
+                }
+            }
+        }
+
+        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){
+            if (ui->Page->HeightCoeff) CPB = ui->B;
+            else CPB = ui->Page->B;
+            if (ui->Page->ScrollerShownV && laIsInBound(x, y, ui->R - LA_SCROLL_W - bt->RP*2, ui->R, ui->Page->U, CPB)){
+                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui;
+            }elif (ui->Page->ScrollerShownH && laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->B - LA_SCROLL_W - bt->BP*2, ui->B)){
+                if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui;
+            }elif (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){
+                if (ParentUi) *ParentUi = ui; uilr->pui=ui;
+                if (tuil = la_DetectUiListRecursiveDeep(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels)) return tuil;
+            }
+        }
+
+        if ((ui->PP.LastPs && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB) && (ui->Subs.pFirst || ui->Page)){
+            if (ui->Page->HeightCoeff) CPB = ui->B;
+            else
+                CPB = ui->Page->B;
+            if (laIsInBound(x, y, ui->Page->R, ui->Page->R + LA_SCROLL_W + bt->RM, ui->Page->U, CPB)){
+                if (ScrollUil) *ScrollUil = ui->Page;
+                if (ParentUi) *ParentUi = ui; uilr->pui=ui;
+            }
+            if (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){
+                if (ParentUi) *ParentUi = ui; uilr->pui=ui;
+                if (tuil = la_DetectUiListRecursiveDeep(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels)) return tuil;
+            }
+        }
+
+        ui = ui->Item.pNext;
+    }
+    return uil;
+}
+
+int la_TestUiListMinumWidth(laUiList *uil){
+    laUiItem *ui, *tui;
+    laBoxedTheme *bt;
+    laUiList *sub;
+    int CPB = 0;
+    int W = 0;
+    int tW, sW, RowMode=0, rW;
+    void *Restore;
+
+    for (ui = uil->UiItems.pFirst; ui;){
+        bt = ui->Type->Theme ? (*ui->Type->Theme) : 0;
+
+        if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){
+            tW = la_TestUiListMinumWidth(ui->Page) + bt->LP + bt->RP;
+            tW = (int)((float)tW / ui->C->PreWidth + 2);
+            if (W < tW) W = tW;
+        }elif (ui->Type == _LA_UI_COLLECTION){
+            Restore = ui->PP.EndInstance;
+            tW = 0; sW = 0;
+            for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+                ui->PP.EndInstance = sub->Instance;
+                sW = la_TestUiListMinumWidth(sub) + bt->LP + bt->RP;
+                if (sW > tW) tW = sW;
+            }
+            ui->PP.EndInstance = Restore;
+            tW = (int)((float)tW / ui->C->PreWidth + 2);
+            tW *= (ui->SymbolID > 0 ? ui->SymbolID : 1);
+            if (W < tW) W = tW;
+        }elif (ui->Type==&_LA_UI_ROW_BEGIN){
+            RowMode=1; rW=0;
+        }elif (ui->Type==&_LA_UI_ROW_END){
+            RowMode=0; rW=(int)((float)rW / ui->C->PreWidth + 2); if (W < rW) W = rW;
+        }elif (ui->Type->GetMinWidth){
+            tW = ui->Type->GetMinWidth(ui) + bt->LP + bt->RP;
+            tW = (int)((float)tW / ui->C->PreWidth + 2);
+            if(RowMode){ rW+=tW; }else{ if (W < tW) W = tW; }
+        }
+        ui = ui->Item.pNext;
+    }
+    return W;
+}
+
+void la_InitLLVM(){
+    //LLVMLinkInMCJIT();
+    //LLVMInitializeNativeTarget();
+    //LLVMInitializeNativeAsmPrinter();
+    //LLVMInitializeNativeAsmParser();
+
+    //   MAIN.llvmContext = LLVMGetGlobalContext();
+    //MAIN.llvmModule = LLVMModuleCreateWithNameInContext(LA_NODE_MAIN_MODULE_NAME, MAIN.llvmContext);
+}
+
+//==================================================================================================
+
+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 la_FreeKeyMapItem(laKeyMapItem* kmi){
+    if(kmi->Instructions) strSafeDestroy(&kmi->Instructions);
+    if(kmi->Operation) strSafeDestroy(&kmi->Operation);
+    if(kmi->Action.Go) la_FreePropStepCache(kmi->Action.Go);
+    if(kmi->Base.Go) la_FreePropStepCache(kmi->Action.Go);
+    memFree(kmi);
+}
+laKeyMapItem *laAssignNewKey(laKeyMapper *km, char *Path, char *Operation, char SelectBase, int SpecialKeyBits, int EventType, int Key, char *ExtraInstructions){
+    laKeyMapItem *kmi;
+
+    if (!km) return 0;
+
+    kmi = memAcquire(sizeof(laKeyMapItem));
+
+    if (la_GetPropFromPath(&kmi->Base, 0, Path, 0)){
+        la_GetPropFromPath(&kmi->Action, &kmi->Base, Operation, 0);
+    }else{
+        strSafeSet(&kmi->Operation, Operation);
+    }
+
+    strSafeSet(&kmi->Instructions, ExtraInstructions);
+
+    kmi->SpecialKeyBits = SpecialKeyBits;
+    kmi->EventType = EventType;
+    kmi->Key = Key;
+    kmi->SelectBase = SelectBase;
+
+    lstAppendItem(&km->Items, kmi);
+
+    return kmi;
+}
+int laKeyMapExecuteEvent(laOperator *from, laKeyMapper *km, laEvent *e){
+    laKeyMapItem *kmi; int inv=0;
+    char *instructions;
+    if(e->Type==LA_MOUSEMOVE) return 0;
+    for (kmi = km->Items.pFirst; kmi; kmi = kmi->Item.pNext){
+        if (kmi->SpecialKeyBits == e->SpecialKeyBit &&
+            kmi->EventType == e->Type && ((kmi->Key == e->Input) || (kmi->Key == e->key))){
+            instructions = kmi->Instructions ? kmi->Instructions->Ptr : 0;
+            if (kmi->Operation)
+                laInvoke(from, kmi->Operation->Ptr, e, 0, instructions, 0);
+            else
+                laInvoke(from, ((laOperatorProp *)&kmi->Action.LastPs)->OperatorID, e, &kmi->Base, instructions, 0);
+            inv = 1;
+        }
+    }
+    return inv;
+}
+int laKeyMapExecuteEventEx(laOperator *from, laPropPack *UiExtra, laKeyMapper *km, laEvent *e){
+    laKeyMapItem *kmi;
+    char *instructions;
+    int inv = 0; int lx = -1, ly = -1;
+    if(e->Type==LA_MOUSEMOVE) return 0;
+    for (kmi = km->Items.pFirst; kmi; kmi = kmi->Item.pNext){
+        if (kmi->SpecialKeyBits == e->SpecialKeyBit &&
+            kmi->EventType == e->Type && ((kmi->Key == e->Input) || (kmi->Key == e->key))){
+            if (e->Localized){
+                lx = e->x;
+                ly = e->y;
+                laLocalToWindow(from, MAIN.ToPanel, &e->x, &e->y);
+                e->Localized = 0;
+            }
+
+            instructions = kmi->Instructions ? kmi->Instructions->Ptr : 0;
+            if (kmi->SelectBase == LA_KM_SEL_UI_EXTRA){
+                laInvoke(from, kmi->Operation->Ptr, e, UiExtra, instructions, 0);
+            }elif (kmi->SelectBase == LA_KM_SEL_PANEL){
+                laInvoke(from, kmi->Operation->Ptr, e, &((laPanel *)MAIN.ToPanel)->PP, instructions, 0);
+            }elif (kmi->Operation){
+                laInvoke(from, kmi->Operation->Ptr, e, 0, instructions, 0);
+            }else{
+                laInvoke(from, ((laOperatorProp *)&kmi->Action.LastPs)->OperatorID, e, &kmi->Base, instructions, 0);
+            }
+            inv = 1;
+
+            if (lx >= 0){
+                e->x = lx;
+                e->y = ly;
+                e->Localized = 1;
+            }
+        }
+    }
+    return inv;
+}
+
+void la_DefaultOperatorParser(laStringSplitor *ss, char *IconID, char *DisplayString);
+
+void la_DestroyOperatorType(laOperatorType* at){
+    //if(at->PC) la_FreePropertyContainer(at->PC);
+    memFree(at);
+}
+laOperatorType *laCreateOperatorType(const char *ID, const char *Name, const char *Description,
+                                     laCheckFunc Check, laInitFunc Init, laExitFunc Exit, laInvokeFunc Invoke, laModalFunc Modal,
+                                     uint32_t IconID, int ExtraMark){
+
+    laOperatorType *at = memAcquire(sizeof(laOperatorType));
+
+    at->Identifier = ID;
+    at->Name = Name;
+    at->Description = Description;
+
+    at->Check = Check;
+    at->Invoke = Invoke;
+    at->Init = Init;
+    at->Exit = Exit;
+    at->Modal = Modal;
+    at->IconID = IconID;
+    at->ExtraMark = ExtraMark;
+
+    at->ParseArgs = la_DefaultOperatorParser;
+
+    hsh256InsertItemCSTR(&MAIN.OperatorTypeHash, at, at->Identifier);
+
+    return at;
+}
+
+laPropContainer* laDefineOperatorProps(laOperatorType* ot, int HyperLevel){
+    ot->PC = memAcquire(sizeof(laPropContainer));
+    ot->PC->Identifier = ot->Identifier;
+    ot->PC->Hyper = HyperLevel; 
+    return ot->PC;
+}
+
+laOperator *la_CreateOperator(laOperatorType *at){
+    laOperator *a = CreateNew(laOperator);
+
+    a->Type = at;
+
+    if (at->PC && at->PC->Props.pFirst){
+        a->PP.LastPs = memAcquireSimple(sizeof(laPropStep));
+        a->PP.LastPs->p = memAcquire(sizeof(laProp));
+        a->PP.LastPs->p->SubProp = at->PC;
+        a->PP.LastPs->p->PropertyType = LA_PROP_SUB;
+        a->PP.LastPs->p->Identifier = at->PC->Identifier;
+        a->PP.LastPs->Type = L'.';
+    }
+
+    return a;
+}
+int la_OperatorTypeByID(laOperatorType *a, char *id){
+    return (!strcmp(a->Identifier, id));
+}
+laOperatorType *laGetOperatorType(const char *ID){
+    return hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);
+}
+
+int laOperatorExistsT(laOperatorType* at){
+    if (!at) return 0;
+    for (laOperator *a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (at == a->Type){ return 1; } }
+    return 0;
+}
+int laOperatorExists(const char* ID){
+    laOperatorType* at=laGetOperatorType(ID); if (!at) return 0;
+    return laOperatorExistsT(at);
+}
+int la_OperatorExists(laOperator *ac){
+    if (!ac) return 0;
+    laOperator *a;
+    for (a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (ac == a){return 1;}}
+    return 0;
+}
+int la_UiOperatorExists(void *inst){
+    laOperator *a;
+    if (!inst) return 0;
+    for (a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){
+        if (((laUiItem *)a->Instance) == inst){
+            return 1;
+        }
+    }
+    for (a = MAIN.CurrentWindow->PendingOperators.pFirst; a; a = a->Item.pNext){
+        if (a->Instance == inst){
+            return 1;
+        }
+    }
+    return 0;
+}
+int la_OperatorPending(laOperator *target){
+    laOperator *a;
+    if (!target) return 0;
+    for (a = MAIN.CurrentWindow->PendingOperators.pFirst; a; a = a->Item.pNext){
+        if (a == target){
+            return 1;
+        }
+    }
+    return 0;
+}
+void laSetOperatorLocalizer(void *ToPanel){
+    MAIN.ToPanel = ToPanel;
+}
+
+void la_DestroyConfirmData(laConfirmData **cd);
+void *la_DestroyOperator(laOperator **a, laListHandle *Operators, int OnlyThisOne){
+    laOperator *ai = (*a);
+    laOperator *ac = ((*a)->Child);
+    void *Ret = 0;
+
+    if (!OnlyThisOne && ac && la_OperatorExists(ac) && !ac->Using){
+        la_DestroyOperator(&ac, Operators, OnlyThisOne);
+    }
+
+    if ((*a)->ConfirmData) la_DestroyConfirmData(&((*a)->ConfirmData));
+
+    if ((*a)->PP.LastPs){
+        memFree((*a)->PP.LastPs->p);
+        memFree((*a)->PP.LastPs);
+    }
+
+    if (laNonFixedPanelExists((*a)->OperatorPanel)){
+        la_SetPropMathcerContext((*a)->OperatorPanel);
+        MAIN.CurrentPanel = (*a)->OperatorPanel;
+        laDestroySinglePanel((*a)->OperatorPanel);
+    }
+    if ((*a)->CreatedThis) FreeMem((*a)->CreatedThis);
+
+    if ((*a)->ExtraInstructionsP) strDestroyStringSplitor(&(*a)->ExtraInstructionsP);
+
+    lstClearPointer(&(*a)->LocalUiLists);
+
+    if (Operators){
+        Ret = ai->Item.pNext;
+        if (la_OperatorPending((*a) /*->Instance*/)) lstRemoveItem(&MAIN.CurrentWindow->PendingOperators, *a);
+        else
+            lstRemoveItem(Operators, *a);
+
+        for (ai = Operators->pFirst; ai; ai = ai->Item.pNext){
+            if (ai->Child == (*a)) ai->Child = 0;
+        }
+    }
+
+    strSafeDestroy(&(*a)->RuntimeHint);
+
+    free(*a);
+    return Ret;
+}
+
+int laOperatorAvailable(char *ID, laPropPack *This, laStringSplitor *Instructions){
+    laOperatorType *at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);
+    if (!at) return 0;
+
+    if (!at->Check) return 1;
+
+    return (at->Check(This, Instructions));
+}
+int laOperatorAvailableP(laOperatorType *at, laPropPack *This, laStringSplitor *Instructions){
+    if (!at) return 0;
+
+    if (!at->Check) return 1;
+
+    return (at->Check(This, Instructions));
+}
+int laOperatorAvailablePSafe(laOperatorType *at, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions){
+    laPropPack FakePP = {0};
+    laPropStep FakePs = {0};
+    if (!at) return 0;
+
+    if (!at->Check) return 1;
+
+    FakePP.LastPs = &FakePs;
+    FakePP.Go = FakePP.LastPs;
+    FakePP.LastPs->p = This->LastPs->p;
+    FakePP.LastPs->UseInstance = This->EndInstance;
+    FakePP.EndInstance = Real_FromInstance;
+    FakePP.LastIndex = This->LastIndex;
+
+    return (at->Check(&FakePP, Instructions));
+}
+int laOperatorAvailableSafe(char *ID, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions){
+    laOperatorType *at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);
+    return laOperatorAvailablePSafe(at, This, Real_FromInstance, Instructions);
+}
+
+int laInvokeUi(laOperator *From, char *ID, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals){
+    laOperatorType *at;
+    laOperator *a, *f = From;
+
+    int rev;
+
+    if (la_UiOperatorExists(inst)) return -1;
+
+    at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);
+    if (!at) return -1;
+
+    a = la_CreateOperator(at);
+    a->Instance = inst;
+    a->ToPanel = MAIN.ToPanel;
+    if (!IgnoreLocals) lstGeneratePointerList(f ? &f->LocalUiLists : 0, Locals, &a->LocalUiLists);
+
+    if (From) f->Child = a;
+
+    a->Using = 1;
+
+    if (at->Init) at->Init(a);
+    rev = at->Invoke(a, e);
+
+    a->Using = 0;
+
+    if (rev & LA_FINISH){
+        a->StopNow = 1; if(From)From->Child=0;
+    }
+    if (rev & LA_BLOCK){
+        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);
+        a->State = rev;
+    }else la_DestroyOperator(&a, 0, 0);
+
+    return rev;
+}
+int laInvokeUiP(laOperator *From, laOperatorType *at, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals){
+    laOperator *a, *f = From;
+    int rev;
+
+    if (!at || (la_UiOperatorExists(inst))){
+        return -1;
+    }
+    a = la_CreateOperator(at);
+    a->Instance = inst;
+    a->ToPanel = MAIN.ToPanel;
+    if (!IgnoreLocals) lstGeneratePointerList(f ? &f->LocalUiLists : 0, Locals, &a->LocalUiLists);
+
+    if (From) f->Child = a;
+
+    a->Using = 1;
+
+    if (at->Init) at->Init(a);
+    rev = at->Invoke(a, e);
+
+    a->Using = 0;
+
+    if (rev & LA_FINISH){
+        a->StopNow = 1; if(From)From->Child=0;
+    }
+    if (rev & LA_BLOCK){
+        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);
+        a->State = rev;
+    }else
+        la_DestroyOperator(&a, 0, 0);
+
+    DEB = a;
+
+    return rev;
+}
+
+int laInvoke(laOperator *From, char *ID, laEvent *e, laPropPack *This, char *args, char *args2){
+    laOperatorType *at;
+    laOperator *a, *f = From;
+    int rev;
+
+    at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);
+    if (!at) return -1;
+
+    if (!f && e && e->Localized) return -1;
+
+    a = la_CreateOperator(at);
+    a->ToPanel = MAIN.ToPanel;
+    a->This = This;
+    a->ExtraInstructions = args;
+    strMakeInstructions(&a->ExtraInstructionsP, args);
+    strMakeInstructions(&a->ExtraInstructionsP, args2);
+    strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions);
+
+    if (!laOperatorAvailableP(at, This, a->ExtraInstructionsP)){
+        la_DestroyOperator(&a, 0, 0);
+        return LA_CANCELED;
+    }
+
+    if (e&&(!e->Localized) && (at->ExtraMark & LA_EXTRA_TO_PANEL)){
+        laWindowToLocal(0, a->ToPanel, &e->x, &e->y);
+        e->Localized = 1;
+    }
+
+    if (e&&e->Localized && (!at->ExtraMark & LA_EXTRA_TO_PANEL)){
+        laLocalToWindow(0, a->ToPanel, &e->x, &e->y);
+        e->Localized = 0;
+    }
+
+    if (From) f->Child = a;
+
+    a->Using = 1;
+
+    if (at->Init) at->Init(a);
+    rev = at->Invoke(a, e);
+
+    a->Using = 0;
+
+    if (rev & LA_FINISH){
+        a->StopNow = 1; if(From)From->Child=0;
+    }
+
+    if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){
+        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);
+        a->State = rev;
+        a->PP.EndInstance = a->CustomData;
+    }else
+        la_DestroyOperator(&a, 0, 0);
+
+    return rev;
+}
+int laInvokeCreateThis(laOperator *From, char *ID, laEvent *e, laPropPack *OrigionalThis, void *FromInstance, char *args, char *args2){
+    laOperatorType *at;
+    laOperator *a, *f = From;
+    int rev;
+    laPropPack *created;
+
+    at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID);
+    if (!at) return -1;
+
+    if (!f && (e && e->Localized) || !OrigionalThis || !OrigionalThis->LastPs) return -1;
+
+    created = CreateNew(laPropPack);
+    created->LastPs = memAcquireSimple(sizeof(laPropStep));
+    created->Go = created->LastPs;
+    created->LastPs->p = OrigionalThis->LastPs->p;
+    created->LastPs->UseInstance = FromInstance;
+    created->EndInstance = FromInstance;
+    created->LastIndex = OrigionalThis->LastIndex;
+
+    a = la_CreateOperator(at);
+    a->ToPanel = MAIN.ToPanel;
+    a->This = created;
+    a->CreatedThis = created;
+    a->ExtraInstructions = args;
+    strMakeInstructions(&a->ExtraInstructionsP, args);
+    strMakeInstructions(&a->ExtraInstructionsP, args2);
+    strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions);
+
+    if (!laOperatorAvailableP(at, created, a->ExtraInstructionsP)){
+        la_DestroyOperator(&a, 0, 0);
+        return LA_CANCELED;
+    }
+
+    lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists);
+
+    if (e&&!e->Localized && at->ExtraMark & LA_EXTRA_TO_PANEL) laWindowToLocal(0, a->ToPanel, &e->x, &e->y);
+
+    if (From) f->Child = a;
+
+    a->Using = 1;
+
+    if (at->Init) at->Init(a);
+    rev = at->Invoke(a, e);
+
+    a->Using = 0;
+
+    if (rev & LA_FINISH){
+        a->StopNow = 1; if(From)From->Child=0;
+    }
+
+    if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){
+        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);
+        a->State = rev;
+        a->PP.EndInstance = a->CustomData;
+    }else
+        la_DestroyOperator(&a, 0, 0);
+
+    return rev;
+}
+int laInvokeP(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *This, char *args, char *args2){
+    laOperator *a, *f = From;
+    int rev;
+
+    if (!f && e&&e->Localized) return -1;
+
+    a = la_CreateOperator(at);
+    a->ToPanel = MAIN.ToPanel;
+    a->This = This;
+    a->ExtraInstructions = args;
+    strMakeInstructions(&a->ExtraInstructionsP, args);
+    strMakeInstructions(&a->ExtraInstructionsP, args2);
+    strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions);
+
+    if (!laOperatorAvailableP(at, This, a->ExtraInstructionsP)){
+        la_DestroyOperator(&a, 0, 0);
+        return LA_CANCELED;
+    }
+
+    lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists);
+
+    if (e&&!e->Localized && at->ExtraMark & LA_EXTRA_TO_PANEL){
+        laWindowToLocal(0, a->ToPanel, &e->x, &e->y);
+        e->Localized = 1;
+    }
+
+    if (e&&e->Localized){
+        if (!at->ExtraMark & LA_EXTRA_TO_PANEL){
+            laLocalToWindow(f, f->ToPanel, &e->x, &e->y);
+            e->Localized = 0;
+        }else{
+            laLocalToWindow(f, f->ToPanel, &e->x, &e->y);
+            laWindowToLocal(a, a->ToPanel, &e->x, &e->y);
+        }
+    }
+
+    if (From) f->Child = a;
+
+    a->Using = 1;
+
+    if (at->Init) at->Init(a);
+    rev = at->Invoke(a, e);
+
+    a->Using = 0;
+
+    if (rev & LA_FINISH){
+        a->StopNow = 1;  if(From)From->Child=0;
+    }
+
+    if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){
+        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);
+        a->State = rev;
+        a->PP.EndInstance = a->CustomData;
+        if (a->PP.LastPs) a->PP.LastPs->Type = L'.';
+    }else
+        la_DestroyOperator(&a, 0, 0);
+
+    return rev;
+}
+int laInvokePCreateThis(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *OrigionalThis, void *FromInstance, char *args, char *args2){
+    laOperator *a, *f = From;
+    int rev;
+    laPropPack *created;
+
+    if (!f && e&&e->Localized || !OrigionalThis || !OrigionalThis->LastPs) return -1;
+
+    created = CreateNew(laPropPack);
+    created->LastPs = memAcquireSimple(sizeof(laPropStep));
+    created->Go = created->LastPs;
+    created->LastPs->p = OrigionalThis->LastPs->p;
+    created->LastPs->UseInstance = FromInstance;
+    created->EndInstance = FromInstance;
+    created->LastIndex = OrigionalThis->LastIndex;
+
+    a = la_CreateOperator(at);
+    a->ToPanel = MAIN.ToPanel;
+    a->This = created;
+    a->CreatedThis = created;
+    a->ExtraInstructions = args;
+    strMakeInstructions(&a->ExtraInstructionsP, args);
+    strMakeInstructions(&a->ExtraInstructionsP, args2);
+    strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions);
+
+    if (!laOperatorAvailableP(at, created, a->ExtraInstructionsP)){
+        la_DestroyOperator(&a, 0, 0);
+        return LA_CANCELED;
+    }
+
+    lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists);
+
+    if (e&&!e->Localized && at->ExtraMark & LA_EXTRA_TO_PANEL) laWindowToLocal(0, a->ToPanel, &e->x, &e->y);
+
+    if (From) f->Child = a;
+
+    a->Using = 1;
+
+    if (at->Init) at->Init(a);
+    rev = at->Invoke(a, e);
+
+    a->Using = 0;
+
+    if (rev & LA_FINISH){
+        a->StopNow = 1; if(From)From->Child=0;
+    }
+
+    if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){
+        lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a);
+        a->State = rev;
+        a->PP.EndInstance = a->CustomData;
+    }else
+        la_DestroyOperator(&a, 0, 0);
+
+    return rev;
+}
+void laRequestDelayEvent(real Seconds){
+    MAIN.DelayTriggered=0; MAIN.DelayStart=MAIN.TimeAccum; MAIN.DelayTime = Seconds; }
+
+int la_UiStillInService(void *UiInstance){
+    laOperator *ai, *dai;
+    for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = ai->Item.pNext){
+        if (ai->Instance == UiInstance) return 1;
+    }
+    return 0;
+}
+void la_StopUiOperatorService(void *UiInstance){
+    laOperator *ai, *dai, *NextAi;
+    if (!MAIN.CurrentWindow) return;
+    for (ai = MAIN.CurrentWindow->PendingOperators.pFirst; ai; ai = NextAi){
+        NextAi = ai->Item.pNext;
+        if (ai->Instance == UiInstance){
+            if (ai->Child){
+                la_StopUiOperatorService(ai->Child->Instance);
+                ai->Child = 0;
+            }
+            laOperator *dai = ai;
+            la_DestroyOperator(&dai, &MAIN.CurrentWindow->PendingOperators, 1);
+            continue;
+        }
+    }
+    for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = NextAi){
+        NextAi = ai->Item.pNext;
+        if (ai->Instance == UiInstance){
+            if (ai->Instance == ai->ToPanel){
+                //laHidePanelWithDissoveEffect(ai->ToPanel);
+                //ai->ToPanel->LaterDestroy = 1;
+            }
+            if (ai->Child && la_OperatorExists(ai->Child)){
+                la_StopUiOperatorService(ai->Child->Instance);
+                //ai->Child = 0;
+            }
+            if (!ai->Using){
+                laOperator *dai = ai;
+                la_DestroyOperator(&dai, &MAIN.CurrentWindow->Operators, 1);
+            }else
+                ai->StopNow = 1;
+        }
+    }
+}
+void la_StopAllOperators(){
+    laOperator *ai, *dai, *NextAi;
+    if (!MAIN.CurrentWindow) return;
+    for (ai = MAIN.CurrentWindow->PendingOperators.pFirst; ai; ai = NextAi){
+        NextAi = ai->Item.pNext;
+        NextAi = la_DestroyOperator(&ai, &MAIN.CurrentWindow->PendingOperators, 1);
+        continue;
+    }
+    for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = NextAi){
+        NextAi = ai->Item.pNext;
+        if (ai->Instance == ai->ToPanel && !ai->ToPanel->IsMenuPanel){
+            laHidePanelWithDissoveEffect(ai->ToPanel);
+            ai->ToPanel->LaterDestroy = 1;
+        }
+        if (!ai->Using){
+            laOperator *dai = ai;
+            la_DestroyOperator(&dai, &MAIN.CurrentWindow->Operators, 1);
+        }else
+            ai->StopNow = 1;
+    }
+}
+
+void la_DestroyConfirmData(laConfirmData **cd){
+    if ((*cd)->CustomData) (*cd)->Destroy((*cd)->CustomData);
+    if ((*cd)->StrData) free((*cd)->StrData);
+    FreeMem((*cd));
+    (*cd) = 0;
+}
+void laConfirmInt(laOperator *a, int Data, int mode){
+    laOperator *ai = a;
+    laConfirmData *cd = CreateNew(laConfirmData);
+
+    cd->IData = Data;
+    cd->Mode = mode;
+
+    ai->NextConfirmData = cd;
+    laRetriggerOperators();
+}
+void laConfirmFloat(laOperator *a, real Data, int mode){
+    laOperator *ai = a;
+    laConfirmData *cd = CreateNew(laConfirmData);
+
+    cd->FData = Data;
+    cd->Mode = mode;
+
+    ai->NextConfirmData = cd;
+    laRetriggerOperators();
+}
+void laConfirmString(laOperator *a, char *Str, int mode){
+    laOperator *ai = a;
+    laConfirmData *cd = CreateNew(laConfirmData);
+    int len = strlen(Str);
+    char *buf = calloc(len + 1, sizeof(char));
+    strcpy(buf, Str);
+
+    cd->StrData = buf;
+    cd->Mode = mode;
+    cd->Destroy = free;
+    ai->NextConfirmData = cd;
+    laRetriggerOperators();
+}
+int laConfirmSameDataIfAny(laOperator *a){
+    laOperator *ai = a;
+    laConfirmData *cd;
+    char *buf = 0;
+
+    if (!ai->ConfirmData || ai->NextConfirmData) return 0;
+
+    cd = CreateNew(laConfirmData);
+
+    if (ai->ConfirmData->StrData){
+        int len = strlen(ai->ConfirmData->StrData);
+        buf = calloc(len + 1, sizeof(char));
+        strcpy(buf, ai->ConfirmData->StrData);
+    }
+
+    //cd->CustomData = cd->CustomData;
+    cd->IData = ai->ConfirmData->IData;
+    cd->FData = ai->ConfirmData->FData;
+    cd->StrData = buf;
+    cd->Mode = ai->ConfirmData->Mode;
+    cd->Destroy = ai->ConfirmData->Destroy;
+    ai->NextConfirmData = cd;
+    laRetriggerOperators();
+
+    return 1;
+}
+void laConfirmUserData(laOperator *a, void *UserData, laConfirmDataDestroyFunc Destroy, int mode){
+    laOperator *ai = a;
+    laConfirmData *cd = CreateNew(laConfirmData);
+
+    cd->CustomData = UserData;
+    cd->Mode = mode;
+    cd->Destroy = Destroy;
+    ai->NextConfirmData = cd;
+    laRetriggerOperators();
+}
+
+int laGetConfirmMode(laOperator *a){
+    return ((laOperator *)a)->ConfirmData->Mode;
+}
+int laGetConfirmInt(laOperator *a){
+    laOperator *ai = a;
+    int rev = ai->ConfirmData->IData;
+
+    la_DestroyConfirmData(&ai->ConfirmData);
+    ai->ConfirmData = 0;
+
+    return rev;
+}
+real laGetConfirmFloat(laOperator *a){
+    laOperator *ai = a;
+    real rev = ai->ConfirmData->FData;
+
+    la_DestroyConfirmData(&ai->ConfirmData);
+    ai->ConfirmData = 0;
+
+    return rev;
+}
+void laGetConfirmString(laOperator *a, char *buf){
+    laOperator *ai = a;
+
+    strcpy(buf, ai->ConfirmData->StrData);
+
+    la_DestroyConfirmData(&ai->ConfirmData);
+    ai->ConfirmData = 0;
+}
+void *laGetConfirmUserData(laOperator *a){
+    laOperator *ai = a;
+    return ai->ConfirmData->CustomData;
+}
+
+void laFinalizeOperators(){
+    laOperatorType *at;
+    laListHandle *lst;
+    int i;
+    for (i = 0; i < 256; i++){
+        lst = &MAIN.OperatorTypeHash.Entries[i];
+        for (at = lst->pFirst; at; at = at->Item.pNext){
+            if (at->PC && at->PC->Props.pFirst){
+                lstAppendItem(&MAIN.PropContainers, at->PC);
+            }
+        }
+    }
+}
+
+int la_UpdateOperatorHints(laWindow* w){
+    laSafeString* ss=0;
+    for(laOperator* o=w->Operators.pFirst;o;o=o->Item.pNext){
+        if(o->RuntimeHint&&o->RuntimeHint->Ptr){ strSafePrint(&ss, "%s | %s  ", o->Type->Name, o->RuntimeHint->Ptr);}
+    }
+    if((w->OperatorHints&&ss&&strSame(ss->Ptr,w->OperatorHints->Ptr))||(!w->OperatorHints&&!ss)){ //pass
+    }else{
+        if(ss){ strSafeSet(&w->OperatorHints,ss->Ptr); } else { strSafeDestroy(&w->OperatorHints); }
+        laNotifyUsers("la.windows.operator_hints");//printf("op hint\n");
+    }
+}
+int la_HandleSingleEvent(laEvent *e, laListHandle *Operators){
+    laOperator *a, *NextA = 0;
+    int Result = 0;
+    laConfirmData *ConfirmData = 0, *NextConfirmData = 0;
+
+    a = Operators->pFirst;
+
+    while (1){
+        if (!a) break;
+
+        if (a->StopNow){
+            NextA = a->Item.pNext;
+            if (a->Type->Exit) a->Type->Exit(a, Result);
+
+            ConfirmData = a->NextConfirmData;
+            if (a->ConfirmData) la_DestroyConfirmData(&a->ConfirmData);
+
+            NextConfirmData = ConfirmData;
+            a->ConfirmData = 0;
+            a->NextConfirmData = 0;
+
+            la_DestroyOperator(&a, Operators, 0);
+            a = NextA;
+            if (a){
+                a->ConfirmData = NextConfirmData;
+            }
+            continue;
+        }
+
+        a->Using = 1;
+
+        la_SetPropMathcerContext(a->ToPanel);
+        laSetOperatorLocalizer(a->ToPanel);
+        MAIN.CurrentPanel = a->ToPanel;
+
+        if (a->Type->ExtraMark & LA_EXTRA_TO_PANEL){
+            laWindowToLocal(a, a->ToPanel, &e->x, &e->y);
+            e->Localized = 1;
+        }
+
+        if (a->State & LA_BLOCK){ Result = a->Type->Modal(a, e); }
+
+        //la_PrintOperatorStack();
+
+        if(Result == LA_OPERATOR_CALLS_SHUTOFF){ return 0; }
+
+        if (a->Type->ExtraMark & LA_EXTRA_TO_PANEL){
+            laLocalToWindow(a, a->ToPanel, &e->x, &e->y);
+            e->Localized = 0;
+        }
+
+        la_SetPropMathcerContext(0);
+        laSetOperatorLocalizer(0);
+        MAIN.CurrentPanel = 0;
+
+        a->Using = 0;
+
+        if (Result & LA_PASS_ON){
+            laConfirmSameDataIfAny(a);
+            NextA = a->Item.pNext;
+        }else{
+            NextA = 0;
+            if (a->NextConfirmData){
+                la_DestroyConfirmData(&a->NextConfirmData);
+            }
+        }
+
+        ConfirmData = a->NextConfirmData;
+        if (a->ConfirmData) la_DestroyConfirmData(&a->ConfirmData);
+
+        NextConfirmData = ConfirmData;
+        a->ConfirmData = 0;
+        a->NextConfirmData = 0;
+
+        if (Result & LA_FINISH || Result == LA_CANCEL || (a->StopNow && a->Using == 0)){
+            if (a->Type->Exit) a->Type->Exit(a, Result);
+            la_DestroyOperator(&a, Operators, 0);
+        }
+
+        a = NextA;
+
+        if (a){
+            a->ConfirmData = NextConfirmData;
+        }
+    }
+    return 1;
+}
+int la_HandleEvents(laWindow *w){
+    laEvent *e, *NextE;
+    laOperator *a;
+    laThreadNotifier *tn;
+
+    MAIN.CurrentWindow=w;
+
+    //pthread_spin_lock(&MAIN.csNotifier);
+    while (tn = lstPopItem(&MAIN.ThreadNotifiers)){
+        //pthread_spin_unlock(&MAIN.csNotifier);
+
+        laNotifyUsers(tn->Path);
+
+        FreeMem(tn);
+
+        //if (MAIN.ThreadNotifiers.pFirst)
+            //pthread_spin_lock(&MAIN.csNotifier);
+    }
+    //pthread_spin_unlock(&MAIN.csNotifier);
+
+    while (1){
+        if (MAIN.ReTriggerOperators) laSendOperatorTriggerEvent();
+        while (w->PendingOperators.pLast){
+            a = w->PendingOperators.pLast;
+            if (a->OperatorPanel){
+                laSetOperatorLocalizer(a->OperatorPanel);
+                if (a->OperatorPanel->Mode == LA_PANEL_FLOATING_TOP)
+                    laInvokeUi(a, "LA_modal_panel_operator", 0, a->OperatorPanel, 0, 1);
+            }
+            lstRemoveItem(&w->PendingOperators, a);
+            lstPushItem(&w->Operators, a);
+        }
+        while (1){
+            if (!w->EventList.pFirst) break;
+
+            e = lstPopItem(&w->EventList);
+
+            if (e && !w->Operators.pFirst){
+                laInvokeUi(0, "LA_window_operator", e, w, 0, 0);
+            }
+
+            if (e) if(!la_HandleSingleEvent(e, &w->Operators)) return 0; //EXIT
+
+            FreeMem(e);
+        }
+        if (!MAIN.ReTriggerOperators) break;
+    }
+    la_UpdateOperatorHints(w);
+    return 1;
+}
+int la_AllowInput(uint32_t ch){
+    if(ch>=32 || ch==L'\n' || ch==L'\t' || ch==L'\b') return 1;
+    return 0;
+}
+int laCopyToClipboard(unsigned char * text){
+	XEvent event; Window owner, window=MAIN.CurrentWindow->win;
+	XSetSelectionOwner(MAIN.dpy, MAIN.selection, window, 0);
+	if (XGetSelectionOwner (MAIN.dpy, MAIN.selection) != window) return;
+    strSafeSet(&MAIN.CopyPending, text);
+}
+int la_ProcessSysMessage(){
+    XEvent e;
+    int type;
+
+    int InputCount = 0, CharCount=0;
+    KeySym InputKeysym = 0;
+    Status InputStatus = 0;
+
+    int SendDelay=0,SendIdle=0;
+    if(!MAIN.DelayTriggered && MAIN.TimeAccum-MAIN.DelayStart>MAIN.DelayTime) SendDelay=1;
+    if(!MAIN.IdleTriggered && MAIN.TimeAccum-MAIN.IdleStart>MAIN.IdleTime) SendIdle=1;
+
+    while(XPending(MAIN.dpy)){
+        XNextEvent(MAIN.dpy, &e);
+        if (XFilterEvent(&e, None)) continue;
+        SendIdle=0; MAIN.IdleStart=MAIN.TimeAccum; MAIN.IdleTriggered=0;
+            
+        switch(e.type){
+        case ConfigureNotify:
+            la_CommandResizeWindow(e.xconfigure.window, e.xconfigure.x, e.xconfigure.y, e.xconfigure.width, e.xconfigure.height);
+            break;
+        case Expose:
+            //glXSwapBuffers(MAIN.dpy,e.xexpose.window);
+            //SwapBuffers(GetDC(hwnd));
+            break;
+        case MotionNotify:
+            la_SendMouseEvent(e.xmotion.window, LA_MOUSEMOVE, e.xmotion.x,e.xmotion.y);
+            break;
+        case ButtonPress:
+            type=LA_MOUSEDOWN;
+            if(e.xbutton.button==1){type|=LA_KEY_MOUSE_LEFT;}
+            elif(e.xbutton.button==2){type|=LA_KEY_MOUSE_MIDDLE;}
+            elif(e.xbutton.button==3){type|=LA_KEY_MOUSE_RIGHT;}
+            elif(e.xbutton.button==4){type=LA_MOUSEUP|LA_KEY_MOUSE_SCROLL;}
+            elif(e.xbutton.button==5){type=LA_MOUSEDOWN|LA_KEY_MOUSE_SCROLL;}
+            la_SendMouseEvent(e.xbutton.window, type, e.xbutton.x,e.xbutton.y);
+            break;
+        case ButtonRelease:
+            type=LA_MOUSEUP;
+            if(e.xbutton.button==1){type|=LA_KEY_MOUSE_LEFT;}
+            elif(e.xbutton.button==2){type|=LA_KEY_MOUSE_MIDDLE;}
+            elif(e.xbutton.button==3){type|=LA_KEY_MOUSE_RIGHT;}
+            la_SendMouseEvent(e.xbutton.window, type, e.xbutton.x,e.xbutton.y);
+            break;
+        case KeyPress:
+                InputCount=Xutf8LookupString(MAIN.ic, (XKeyPressedEvent*)&e, MAIN.InputBuf, MAIN.InputBufMax, &InputKeysym, &InputStatus);
+                MAIN.InputBuf[InputCount]=0;
+                if (InputStatus==XBufferOverflow)  printf("XInputBufferOverflow\n");
+                if (InputStatus == XLookupKeySym || InputStatus == XLookupBoth) { /*printf("status: %d\n", InputStatus);*/ }
+                /*printf("pressed KEY: %d\n", (int)InputKeysym);*/
+            if (InputCount){ MAIN.InputBuf[InputCount]=0; } strToUnicode(MAIN.InputBufU,MAIN.InputBuf); int UCount=strlenU(MAIN.InputBufU);
+            for(int i=0;i<UCount;i++){ if(la_AllowInput(MAIN.InputBufU[i])) la_SendInputEvent(e.xkey.window, MAIN.InputBufU[i]); }
+            if(InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 0)){
+                la_SendKeyboardEvent(e.xkey.window, LA_KEY_DOWN, la_TranslateSpecialKey(InputKeysym));
+            }
+            break;
+        case KeyRelease:
+            if(InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 0)){
+                la_SendKeyboardEvent(e.xkey.window, LA_KEY_UP, la_TranslateSpecialKey(InputKeysym));
+            }
+        case ClientMessage:
+            if(e.xclient.data.l[0]==MAIN.MsgDelWindow){
+                if(la_OnWindowDestroy(e.xclient.window)){ return 0; }
+            }
+            break;
+        case SelectionNotify:
+            if(e.xselection.selection != MAIN.bufid) continue;
+            if (e.xselection.property){
+                char *result; unsigned long ressize, restail; int resbits; Atom fmtid;
+                XGetWindowProperty(MAIN.dpy, MAIN.CurrentWindow->win, MAIN.propid, 0, LONG_MAX/4, False, AnyPropertyType,
+                &fmtid, &resbits, &ressize, &restail, (unsigned char**)&result);
+
+                if (fmtid == MAIN.incrid) logPrintNew("Pasted buffer is too large and INCR reading is not implemented yet.\n");
+                else if(result) {
+                    arrEnsureLength(&MAIN.InputBufU, strlen(result), &MAIN.InputBufUMax, sizeof(uint32_t));
+                    strToUnicode(MAIN.InputBufU,result); int UCount=strlenU(MAIN.InputBufU);
+                    for(int i=0;i<UCount;i++){ if(la_AllowInput(MAIN.InputBufU[i])) la_SendInputEvent(e.xkey.window, MAIN.InputBufU[i]); }
+                }
+
+                XFree(result);
+                return True;
+            }
+        case SelectionRequest:
+            if(!MAIN.CopyPending){ break; }
+            char* text=MAIN.CopyPending->Ptr; int size=strlen(text);
+			if (e.xselectionrequest.selection != MAIN.selection) break;
+			XSelectionRequestEvent * xsr = &e.xselectionrequest;
+			XSelectionEvent ev = {0};
+			int R = 0;
+			ev.type = SelectionNotify, ev.display = xsr->display, ev.requestor = xsr->requestor,
+			ev.selection = xsr->selection, ev.time = xsr->time, ev.target = xsr->target, ev.property = xsr->property;
+			if (ev.target == MAIN.targets_atom) R = XChangeProperty (ev.display, ev.requestor, ev.property, XA_ATOM, 32,
+					PropModeReplace, (unsigned char*)&MAIN.UTF8, 1);
+			else if (ev.target == XA_STRING || ev.target == MAIN.text_atom) 
+				R = XChangeProperty(ev.display, ev.requestor, ev.property, XA_STRING, 8, PropModeReplace, text, size);
+			else if (ev.target == MAIN.UTF8)
+				R = XChangeProperty(ev.display, ev.requestor, ev.property, MAIN.UTF8, 8, PropModeReplace, text, size);
+			else ev.property = None;
+			if ((R & 2) == 0) XSendEvent (MAIN.dpy, ev.requestor, 0, 0, (XEvent *)&ev);
+			break;
+        case SelectionClear:
+			return;
+        default:
+            break;
+        }
+    }
+
+    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
+        if(SendDelay) { la_SendTimerEvent(w->win, LA_TIME_DELAY); MAIN.DelayTriggered=1; }
+        if(SendIdle) { la_SendTimerEvent(w->win, LA_TIME_IDLE);  MAIN.IdleTriggered=1; }
+    }
+
+    return 1;
+};
+
+void la_PrintOperatorStack(){
+    laWindow *w = MAIN.CurrentWindow;
+    laOperator *a;
+    printf("\n");
+    for (a = w->Operators.pFirst; a; a = a->Item.pNext){
+        printf("OP [%-25s] For [0x%08x]  Child[%-25s][0x%08x]\n",
+               a->Type->Identifier, a->Instance,
+               (a->Child ? a->Child->Type->Identifier : ""), a->Child);
+    }
+}
+
+int la_DrawWindow(laWindow *w){
+    MAIN.CurrentWindow = w;
+    la_WindowDefDraw(w, 0);
+}
+void laMainLoop(){
+    laWindow *w = MAIN.Windows.pFirst, *NextW;
+    laTimeRecorder FrameStartTime, FrameEndTime;
+    time_t t1, t2;
+    real TimeInterval, Pause, TimeAccum = 0, FrameInterval;
+    static int a = 0;
+
+    if(!laValidateProperties()){ laShutoff(); return; }
+
+    MAIN.DelayTriggered=1;
+
+    laCopyToClipboard("Hello clipboard!");
+
+    while (1){
+        laRecordTime(&FrameStartTime);
+
+        if(!la_ProcessSysMessage()){ return; }
+
+        la_UpdateControllerStatus();
+
+        for (w=MAIN.Windows.pFirst;w;w = NextW){
+            NextW = w->Item.pNext;
+            if(!la_HandleEvents(w)) return;
+        }
+        for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
+            tnsSwitchToCurrentWindowContext(w);
+            la_DrawWindow(w);
+        }
+        for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){
+            glXSwapBuffers(MAIN.dpy, w->win);
+        }
+        //t2 = clock();
+        laRecordTime(&FrameEndTime);
+        TimeInterval = /* (t2 - t1) / 1000.0;*/ laTimeElapsedSecondsf(&FrameEndTime, &FrameStartTime);
+        Pause = (1.0 / MAIN.TopFramerate - TimeInterval);
+
+        if (Pause > 0){
+            int ms = Pause * 1000000.0;
+            usleep(ms);
+        }
+
+        laRecordTime(&FrameEndTime);
+        TimeInterval = /* (t2 - t1) / 1000.0;*/ laTimeElapsedSecondsf(&FrameEndTime, &FrameStartTime);
+
+        MAIN.TimeAccum += (MAIN.LastFrameTime = (Pause + TimeInterval));
+        FrameInterval = 1.0 / MAIN.Animation.FrameRate;
+    }
+}

+ 209 - 0
source/lagui/la_resource.c

@@ -0,0 +1,209 @@
+#include "la_5.h"
+
+extern LA MAIN;
+extern struct _tnsMain *T;
+
+
+laUiType *_LA_UI_FIXED_GROUP;
+laUiType *_LA_UI_TAB;
+laUiType _LA_UI_CONDITION;      //NO PTR
+laUiType _LA_UI_CONDITION_END;  //NO PTR
+laUiType _LA_UI_CONDITION_ELSE; //NO PTR
+laUiType _LA_UI_ROW_BEGIN;      //NO PTR
+laUiType _LA_UI_ROW_END;        //NO PTR
+laUiType *_LA_UI_COLLECTION;
+laUiType *_LA_UI_COLLECTION_ITEM;
+laUiType *_LA_UI_COLLECTION_SELECTOR;
+laUiType *_LA_UI_COLLECTION_SINGLE;
+laUiType *_LA_UI_BUTTON;
+laUiType *_LA_UI_LABEL;
+laUiType *_LA_UI_INT;
+laUiType *_LA_UI_INT_METER;
+laUiType *_LA_UI_INT_METER_2D;
+laUiType *_LA_UI_FLOAT;
+laUiType *_LA_UI_FLOAT_COLOR;
+laUiType *_LA_UI_FLOAT_HCY;
+laUiType *_LA_UI_ENUM_SELECTOR;
+laUiType *_LA_UI_MENU_ROOT;
+laUiType *_LA_UI_CONDITION_TOGGLE;
+laUiType *_LA_UI_STRING;
+laUiType *_LA_UI_STRING_MULTI;
+laUiType *_LA_UI_ALIGN;
+laUiType *_LA_UI_CANVAS;
+laUiType *_LA_UI_COLUMN_ADJUSTER;
+laUiType *_LA_UI_SYMBOL;
+laUiType *_LA_UI_COLUMN_VIEWER;
+laUiType *_LA_UI_NODE_SOCKET;
+laUiType *_LA_UI_HEIGHT_ADJUSTER;
+laUiType *_LA_UI_RAW;
+
+laUiDefineFunc _LA_SUBPROP_DONT_CARE;
+
+laBoxedTheme *_LA_THEME_PANEL;
+laBoxedTheme *_LA_THEME_VALUATOR;
+laBoxedTheme *_LA_THEME_BUTTON;
+laBoxedTheme *_LA_THEME_STRING;
+laBoxedTheme *_LA_THEME_SELECTOR;
+laBoxedTheme *_LA_THEME_COLLECTION_SELECTOR;
+laBoxedTheme *_LA_THEME_LABEL;
+laBoxedTheme *_LA_THEME_TAB;
+laBoxedTheme *_LA_THEME_COLLECTION_GROUP;
+laBoxedTheme *_LA_THEME_COLLECTION_ITEM;
+laBoxedTheme *_LA_THEME_FLOATING_PANEL;
+laBoxedTheme *_LA_THEME_3D_VIEW;
+laBoxedTheme *_LA_THEME_2D_VIEW;
+laBoxedTheme *_LA_THEME_SOCKET;
+
+laProp *_LA_PROP_PANEL;
+laProp *_LA_PROP_BLOCK;
+laProp *_LA_PROP_WINDOW;
+laProp *_LA_PROP_UI_ITEM;
+laProp *_LA_PROP_FAILED_ITEM;
+laProp *_LA_PROP_TRASH_ITEM;
+laProp *_LA_PROP_NODE_GRAPH;
+laPropContainer *_LA_PROP_3D_EXTRA;
+laPropContainer *_LA_PROP_2D_EXTRA;
+laPropContainer *_LA_PROP_FILE_BROWSER;
+
+laProp _P_LA_USE_INSTANCE_ONLY;
+
+void la_RegisterMainOperators(){
+    la_RegisterUiOperatorsBasic();
+    la_RegisterViewerOperators();
+    la_RegisterBuiltinOperators();
+}
+
+void la_RegisterMainUiTypes(){
+    la_RegisterUiTypesBasic();
+    la_RegisterUiTypesViewerWidgets();
+}
+
+void la_RegisterWindowKeys(){
+    laKeyMapper* km=&MAIN.KeyMap;
+    laAssignNewKey(km, 0, "LA_udf_append", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'o', 0);
+    laAssignNewKey(km, 0, "LA_managed_save", 0, LA_KEY_CTRL, LA_KEY_DOWN, 's', "quiet=true;");
+    laAssignNewKey(km, 0, "LA_managed_save", 0, LA_KEY_CTRL|LA_KEY_SHIFT, LA_KEY_DOWN, 's', 0);
+    laAssignNewKey(km, 0, "LA_manage_udf", 0, LA_KEY_SHIFT, LA_KEY_DOWN, 'r', 0);
+    laAssignNewKey(km, 0, "LA_switch_layout", 0, LA_KEY_CTRL, LA_KEY_DOWN, LA_KEY_ARRLEFT, "reverse=true;");
+    laAssignNewKey(km, 0, "LA_switch_layout", 0, LA_KEY_CTRL, LA_KEY_DOWN, LA_KEY_ARRRIGHT, 0);
+    laAssignNewKey(km, 0, "LA_system_paste", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'v', 0);
+    laAssignNewKey(km, 0, "LA_undo", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'z', 0);
+    laAssignNewKey(km, 0, "LA_redo", 0, LA_KEY_CTRL|LA_KEY_SHIFT, LA_KEY_DOWN, 'z', 0);
+}
+
+void la_RegisterMainThemes(){
+    laBoxedTheme *bt;
+
+    strSafeSet(&MAIN.example_string,
+"hello(){\n"
+"    world!\n"
+"    This is a LaGUI application 🤔\n"
+"    Now with monospace font support :D\n    And when mixing characters, advances would be correct.\n"
+"}");
+
+    la_UDFAppendSharedTypePointer("BT Panel", &_LA_THEME_PANEL);
+    la_UDFAppendSharedTypePointer("BT Floating Panel", &_LA_THEME_FLOATING_PANEL);
+    la_UDFAppendSharedTypePointer("BT Valuator", &_LA_THEME_VALUATOR);
+    la_UDFAppendSharedTypePointer("BT Button", &_LA_THEME_BUTTON);
+    la_UDFAppendSharedTypePointer("BT String", &_LA_THEME_STRING);
+    la_UDFAppendSharedTypePointer("BT Selector", &_LA_THEME_SELECTOR);
+    la_UDFAppendSharedTypePointer("BT Collection Selector", &_LA_THEME_COLLECTION_SELECTOR);
+    la_UDFAppendSharedTypePointer("BT Label", &_LA_THEME_LABEL);
+    la_UDFAppendSharedTypePointer("BT Tab", &_LA_THEME_TAB);
+    la_UDFAppendSharedTypePointer("BT Collection Group", &_LA_THEME_COLLECTION_GROUP);
+    la_UDFAppendSharedTypePointer("BT Collection Item", &_LA_THEME_COLLECTION_ITEM);
+    la_UDFAppendSharedTypePointer("BT 3D Viewer", &_LA_THEME_3D_VIEW);
+    la_UDFAppendSharedTypePointer("BT 2D Viewer", &_LA_THEME_2D_VIEW);
+    la_UDFAppendSharedTypePointer("BT Socket", &_LA_THEME_SOCKET);
+
+    laTheme *t;
+
+    t = laDesignTheme("Classic Light", "YimingWu");{
+        LA_SET3(t->Color, 0.58,0.58,0.55);
+        LA_SET3(t->AccentColor, 0.1,0.1,0.4);
+        t->InactiveMix=0.7; t->InactiveSaturation=0.2;
+        t->CursorAlpha=0.9; t->SelectionAlpha=0.3;
+        t->WireBrightness=0.5; t->WireSaturation=0.6; t->WireTransparency=0.65;
+        t->EdgeBrightness=0.65; t->EdgeTransparency=0.8; t->VertexBrightness=0.65, t->VertexTransparency=0.9;
+        t->SelectedFaceTransparency=0.6,t->SelectedEdgeTransparency=0.9, t->SelectedVertexTransparency=1.0;
+        laDesignBoxedTheme(t, "Panel",&_LA_THEME_PANEL,
+            0.85, 0.5, 0.2, 0.15, 0.1, 0.9, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Floating Panel",&_LA_THEME_FLOATING_PANEL,
+            0.95, 0.8, 0.1, 0.15, 0.1, 0.9, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Valuator",&_LA_THEME_VALUATOR,
+            0.8, 0.5, 0.3, 0.2, 0.1, 0.9, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Button",&_LA_THEME_BUTTON,
+            0.97, 0.2, 0.3, 0.2, 0.9, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "String",&_LA_THEME_STRING,
+            0.9, 0.95, 0.3, 0.2, 0.1, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Selector",&_LA_THEME_SELECTOR,
+            0.85, 0.7, 0.3, 0.2, 0.1, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Collection Selector",&_LA_THEME_COLLECTION_SELECTOR,
+            0.85, 0.7, 0.3, 0.2, 0.1, 0.95, -0.11, 1, -0.11, -0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Label",&_LA_THEME_LABEL,
+            0.7, 0.8, 0.3, 0.1, 0.05, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Tab",&_LA_THEME_TAB,
+            0.9, 0.8, 0.2, 0.1, 0.7, 0.9, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Socket",&_LA_THEME_SOCKET,
+            0.97, 0.2, 0.3, 0.2, 0.9, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Collection Group",&_LA_THEME_COLLECTION_GROUP,
+            0.75, 0.65, 0.2, 0.1, 0.7, 0.3, 0.11, 0.11, 0, 0, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "Collection Item",&_LA_THEME_COLLECTION_ITEM,
+            0.75, 0.65, 0.2, 0.1, 0.7, 0.3, 0.11, 0.11, 0, 0, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "3D Viewer",&_LA_THEME_3D_VIEW,
+            0.75, 0.65, 0.2, 0.1, 0.7, 0.3, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        laDesignBoxedTheme(t, "2D Viewer",&_LA_THEME_2D_VIEW,
+            0.75, 0.65, 0.2, 0.1, 0.7, 0.3, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+
+        la_RefreshThemeColor(t);
+    }
+
+    laTheme* t1=t;
+
+    t = laDesignTheme("Classic Dark", "YimingWu");{
+        LA_SET3(t->Color, 0.5,0.4,0.3);
+        LA_SET3(t->AccentColor, 0.17,0.74,0.49);
+        t->InactiveMix=0.7; t->InactiveSaturation=0.2;
+        t->CursorAlpha=0.9; t->SelectionAlpha=0.3;
+        t->WireBrightness=0.6; t->WireSaturation=0.7; t->WireTransparency=0.65;
+        t->EdgeBrightness=0.05; t->EdgeTransparency=0.8; t->VertexBrightness=0.05, t->VertexTransparency=0.9;
+        t->SelectedFaceTransparency=0.6,t->SelectedEdgeTransparency=0.9, t->SelectedVertexTransparency=1.0;
+        bt = laDesignBoxedTheme(t, "Panel",&_LA_THEME_PANEL,
+            0.2, 0.2, 0.1, 0.8, 0.9, 0.8, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+            memAssignRef(bt, &bt->Parent, t1);
+        bt = laDesignBoxedTheme(t, "Floating Panel",&_LA_THEME_FLOATING_PANEL,
+            0.05, 0.05, 0.4, 0.8, 0.9, 0.8, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+            memAssignRef(bt, &bt->Parent, t1);
+        bt = laDesignBoxedTheme(t, "Valuator",&_LA_THEME_VALUATOR,
+            0.3, 0.1, 0.4, 0.8, 0.9, 0.9, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+            memAssignRef(bt, &bt->Parent, t1);
+        bt = laDesignBoxedTheme(t, "Button",&_LA_THEME_BUTTON,
+            0.1, 0.9, 0.3, 0.8, 0.1, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "String",&_LA_THEME_STRING,
+            0.1, 0.03, 0.3, 0.8, 0.9, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Selector",&_LA_THEME_SELECTOR,
+            0.15, 0.7, 0.3, 0.8, 0.2, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Collection Selector",&_LA_THEME_COLLECTION_SELECTOR,
+            0.15, 0.1, 0.3, 0.8, 0.9, 0.95, -0.11, 1, -0.11, -0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Label",&_LA_THEME_LABEL,
+            0.15, 0.1, 0.3, 0.8, 0.9, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Tab",&_LA_THEME_TAB,
+            0.2, 0.3, 0.8, 0.7, 0.1, 0.9, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Socket",&_LA_THEME_SOCKET,
+            0.1, 0.65, 0.7, 0.8, 0.1, 0.95, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Collection Group",&_LA_THEME_COLLECTION_GROUP,
+            0.25, 0.35, 0.8, 0.7, 0.1, 0.3, 0.11, 0.11, 0, 0, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "Collection Item",&_LA_THEME_COLLECTION_ITEM,
+            0.25, 0.35, 0.8, 0.7, 0.1, 0.3, 0.11, 0.11, 0, 0, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "3D Viewer",&_LA_THEME_3D_VIEW,
+            0.25, 0.35, 0.8, 0.7, 0.1, 0.3, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+        bt = laDesignBoxedTheme(t, "2D Viewer",&_LA_THEME_2D_VIEW,
+            0.25, 0.35, 0.8, 0.7, 0.1, 0.3, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11, 0.11);
+
+        la_RefreshThemeColor(t);
+    }
+}
+
+void la_RegisterInternalTemplates(){
+    la_RegisterBuiltinTemplates();
+}

+ 1259 - 0
source/lagui/la_tns.h

@@ -0,0 +1,1259 @@
+#pragma once
+
+#include "la_5.h"
+//#include "tinycthread.h"
+#include <float.h>
+
+#define TNS_PI 3.1415926535897932384626433832795
+#define deg(r) r / TNS_PI * 180.0
+#define rad(d) d *TNS_PI / 180.0
+
+//typedef real tnsMatrix33d[9];
+
+typedef float tnsMatrix44f[16];
+
+typedef real tnsMatrix44d[16];
+typedef real tnsVector2d[2];
+typedef real tnsVector3d[3];
+typedef real tnsVector4d[4];
+
+typedef float tnsVector3f[3];
+
+typedef int tnsVector2i[2];
+
+//typedef double tnsMatrix33d[9];
+//typedef double tnsMatrix44d[16];
+//
+typedef struct _tnsMatrixStackItem tnsMatrixStackItem;
+struct _tnsMatrixStackItem
+{
+    tnsMatrix44d view;
+    tnsMatrix44d model;
+    tnsMatrix44d projection;
+};
+typedef struct _tnsMatrixStack tnsMatrixStack;
+struct _tnsMatrixStack
+{
+    tnsMatrixStackItem *level;
+    int current_level;
+    int max_level;
+};
+
+typedef struct _tnsShader tnsShader;
+struct _tnsShader{
+    laListItem Item;
+    int vtShaderID;
+    int fgShaderID;
+    int gsShaderID;
+    int glProgramID;
+
+    int CustomID;
+
+    int iModel, iProjection, iView, iProjectionInverse;
+    int iShadow;
+
+    int iVertex, iNormal, iColor, iUV;
+
+    int iTexColor;
+    int iTexColorMS;
+    int iMultiplyColor, StateMultiplyColor;
+    int iTextureMode, StateTextureMode;
+    int iSampleAmount, StateSampleAmount;
+
+    int uViewDir,uViewPos,uFOV;
+};
+typedef struct _tnsTexture tnsTexture;
+typedef struct _tnsCommand tnsCommand;
+struct _tnsCommand
+{
+    GLenum Mode;
+    short Dimensions; // 2 or 3
+    short UVDimensions; // 2 or 3
+    char UseVert;
+    char UseColor;
+    char UseNormal;
+    char UseTexCoord;
+    char UseIndex;
+    GLenum PolyMode; //0-solid 1-wire
+    GLenum Shade;    //0-falt 1-smooth
+    GLfloat UniformColor[4];
+
+    short NumVert;
+    short NumIndex;
+    short VertBegin;
+    short VertEnd; //'END'is the next one after the last one.
+    short ColorBegin;
+    short ColorEnd;
+    short TexCoordBegin;
+    short TexCoordEnd;
+    short NormalBegin;
+    short NormalEnd;
+    GLushort IndexBegin;
+    GLushort IndexEnd;
+
+    tnsShader *ReplaceShader;
+    tnsTexture *ColorTexture;
+    int TextureMode;
+    int MultiplyColor;
+};
+typedef struct _tnsMain tnsMain;
+typedef struct _tnsWorld tnsWorld;
+typedef struct _tnsObject tnsObject;
+struct _tnsWorld
+{
+    laListItem Item;
+    laListHandle RootObjects;
+    tnsObject *ActiveRoot;
+
+    laListHandle AllObjects;
+    laListHandle Materials;
+
+    u16bit TimeYear;
+    u8bit TimeMonth;
+    u8bit TimeDay;
+
+    laListHandle BezierCurves;
+    laListHandle Meshes;
+};
+
+NEED_STRUCTURE(tnsLoopItem);
+NEED_STRUCTURE(tnsRenderLine);
+NEED_STRUCTURE(tnsRenderBuffer);
+
+STRUCTURE(tnsFilterKernel){
+    int Size;
+    real *Kernel;
+};
+
+STRUCTURE(tnsTriangulateNode){
+    char Picked;
+    real Angle; //rad
+    tnsLoopItem *LoopItem;
+    tnsRenderLine *FowardRL;
+    tnsRenderLine *BackwardRL;
+};
+STRUCTURE(tnsTriangulateEdgeNode){
+    tnsRenderLine *RL;
+};
+
+struct _tnsMain
+{
+    laListItem Item;
+
+    tnsMatrixStack stack;
+
+    laListHandle Shaders;
+    int NextShaderIndex;
+    tnsShader *CurrentShader;
+    tnsShader *BindedShader;
+
+    //int            MatrixMode;
+    int IsOffscreen;
+    laListHandle Offscreens;
+
+    char *GLVersionStr;
+    char *GLVendorStr;
+    char *GLRendererStr;
+    char *GLSLVersionStr;
+
+    tnsShader* immShader;
+    tnsShader* RayShader;
+    tnsShader* ShadowShader;
+    tnsShader* SceneShader;
+    tnsShader* SelectionShader;
+
+    int GlobalVAO;
+
+    tnsShader *uiShader;
+    tnsShader *stringShader;
+    tnsShader *TextureShader;
+    tnsShader *RectangleTextureShader;
+    tnsShader *TextureMultiplyShader;
+    tnsShader *MSTextureShader;
+    tnsShader *MSATextureShader;
+    tnsShader *TEST_MatcapShader;
+    tnsShader *TransparentGridShader;
+    tnsShader *SobelColorShader;
+    tnsShader *SobelShader;
+    tnsShader *ExtraBuffersShader;
+
+    laListHandle Textures;
+    tnsTexture *PreviewTexture;
+
+    tnsFilterKernel EdgeGaussFilter;
+
+    GLenum GlTextureSets;
+
+    // Corresponds to current GL_TEXTURE0/1...
+    tnsTexture *TexColor;
+    tnsTexture *TexRenderbuffer;
+
+    // For commands
+    GLenum StateShadeMode;
+    GLenum StatePolyMode;
+    tnsTexture *StateTexColor;
+    int StateTextureMode;
+    int StateMultiplyColor;
+    
+    tnsShader* StateShader;
+
+    GLfloat StateColor[4];
+
+    GLfloat* Vert;
+    GLuint VertBufObject;
+    int NextVert, MaxVert;
+
+    GLfloat* Color;
+    GLuint ColorBufObject;
+    int NextColor, MaxColor;
+
+    GLfloat* Normal;
+    GLuint NormalBufObject;
+    int NextNormal, MaxNormal;
+
+    GLfloat* TexCoord;
+    GLuint TexCoordBufObject;
+    int NextTexCoord, MaxTexCoord;
+
+    GLuint* Index;
+    GLuint IndexBufObject;
+    int NextIndex, MaxIndex;
+
+    tnsCommand* DrawingCommand;
+    int NextCommand, MaxCommand;
+
+    tnsWorld World;
+
+    laListHandle RenderBuffers;
+    tnsRenderBuffer *ActiveRenderBuffer;
+};
+
+typedef struct _tnsLineStripPoint tnsLineStripPoint;
+struct _tnsLineStripPoint
+{
+    laListItem Item;
+    tnsVector3d P;
+};
+
+typedef struct _tnsLineStrip tnsLineStrip;
+struct _tnsLineStrip
+{
+    laListItem Item;
+    laListHandle Points;
+    int PointCount;
+};
+
+#define TNS_SNAKE_STRENGTH_LIMIT 30
+#define TNS_SNAKE_STEP_LENGTH 5
+#define TNS_SNAKE_STRENGTH_MARCHING_LIMIT 30
+
+#define TNS_SNAKE_EDGE_WIDTH 2
+#define TNS_SNAKE_FILTER_SIZE 6
+#define TNS_SNAKE_ANGLE_DEVIATE 0.5
+#define TNS_SNAKE_ANGLE_PRICISION 1
+#define TNS_SNAKE_STEP1 3
+#define TNS_SNAKE_STEP2 5
+
+typedef struct _tnsTextureSample tnsTextureSample;
+struct _tnsTextureSample
+{
+    laListItem Item;
+    u8bit Sample;
+    int X, Y;
+    real Z;
+};
+
+typedef struct _tnsTexture tnsTexture;
+struct _tnsTexture
+{
+    laListItem Item;
+
+    int IsRenderBuffer;
+
+    GLuint GLTexHandle;
+    GLint GLTexBitsType; //like GL_RGBA
+    GLuint GLTexType; //like GL_TEXTURE_2D
+    int Multisample;
+    int Width;
+    int Height;
+
+    void *DrawData;
+
+    int RBWidth, RBHeight;
+    int ElemSize;
+    void *TextureReadBack;
+    void **SamplePtr;
+    laListHandle PendingSamples;
+    laListHandle ErasedSamples;
+
+    laListHandle LineStrips;
+};
+
+typedef struct _tnsOffscreen tnsOffscreen;
+struct _tnsOffscreen
+{
+    laListItem Item;
+
+    tnsTexture *pColor[16];
+    tnsTexture *pDepth;
+    tnsTexture *pStencil;
+
+    GLuint FboHandle;
+
+    int UseSecondary;
+};
+
+extern const GLuint TNS_ATTACHMENT_ARRAY_NONE[];
+extern const GLuint TNS_ATTACHMENT_ARRAY[];
+extern const GLuint TNS_ATTACHMENT_ARRAY_1[];
+extern const GLuint TNS_ATTACHMENT_ARRAY_2[];
+extern const GLuint TNS_ATTACHMENT_ARRAY_1_2[];
+extern const GLuint TNS_ATTACHMENT_ARRAY_0_1_2[];
+extern const GLenum TNS_WINDOW_DRAWBUFFER_ARRAY[];
+
+#define TNS_PROJECTION_MATRIX 1
+#define TNS_MODEL_MATRIX 2
+#define TNS_VIEW_MATRIX 3
+#define TNS_TEXTURE_MATRIX 4
+
+//==========================================================================[FT]
+#include "freetype/ftglyph.h"
+#include "freetype/ftoutln.h"
+#include "freetype/fttrigon.h"
+#include "ft2build.h"
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+NEED_STRUCTURE(tnsTexture);
+
+typedef struct _tnsFontSingleCharacter tnsFontSingleCharacter;
+struct _tnsFontSingleCharacter
+{
+    tnsTexture *Tex;
+    int Generated;
+    short width;
+    short height;
+    short advx;
+    short advy;
+    short deltax;
+    short deltay;
+
+    short bufferx;
+    short buffery;
+};
+
+
+#define TNS_UNICODE_COUNT ((unsigned int)(1<<17))
+#define TNS_MONO_COUNT (0x045f)
+
+typedef struct _tnsFont tnsFont;
+struct _tnsFont
+{
+    laListItem Item;
+
+    char *fontName;
+    char *IconFontName;
+
+    tnsFontSingleCharacter** characters; /* [(1<<17)] TNS_UNICODE_COUNT Unicode plane 0-1 */
+    tnsFontSingleCharacter** monocharacters; /* [0x045f] TNS_MONO_COUNT Up to cryllic. */
+
+    FT_Library ftlib;
+    FT_Face ftface[16];
+    FT_Face ftfacemono;
+    int NumFaces;/* excludes mono. */
+    real MonoScale;
+    int MonoAdvance;
+
+    real size;
+    unsigned int height;
+
+    tnsTexture TexBuffer;
+    int CurrentX;
+    int CurrentY;
+};
+
+typedef struct _tnsFontManager tnsFontManager;
+struct _tnsFontManager
+{
+    laListHandle Fonts;
+    tnsFont *UsingFont;
+
+    tnsFont *VectorsGrapghs;
+
+    unsigned LastDlst;
+};
+
+typedef struct _tnsFontBoundBox tnsFontBoundBox;
+struct _tnsFontBoundBox
+{
+    int x, y, w, h; /* Upper Left and width,height */
+};
+
+#define TNS_FONT_BUFFER_W 2048
+#define TNS_FONT_BUFFER_H 2048
+
+#define TNS_FONT_ALIGN_LEFT 1
+#define TNS_FONT_ALIGN_CENTER 2
+#define TNS_FONT_ALIGN_RIGHT 4
+#define TNS_FONT_ALIGN_LEFT_PROTECT 8
+#define TNS_FONT_ALIGN_CENTER_FIRST (2 | 8)
+
+#define CSS_FLOW_DIRECTION_LR 1
+#define CSS_FLOW_DIRECTION_TD 0
+
+//typedef struct _tnsCssBorder tnsCssBorder;
+//struct _tnsCssBorder{
+//	real Px;//thickness
+//	real Color[4];//rgba
+//	int   Style;//Like________ or ....... or __.__.__. or ======== or ~~~~~~~
+//	int   Padding;
+//	int   Margin;
+//};
+//
+//typedef struct _tnsCssBackground tnsCssBackground;
+//struct _tnsCssBackground{
+//	real Color[4];
+//	int   ImageID;//LA SPECIFIC
+//	int   Repeat;
+//	int   PositionFixed;
+//	real PositionRatio;
+//};
+//
+//typedef struct _tnsCssText tnsCssText;
+//struct _tnsCssText{
+//	real Color[4];
+//	int LineSpacing;
+//	int LetterSpacing;
+//	int Align;//0-LR 1-C 2-L 3-R all support number-ready display
+//	int Decoration;
+//	int Underline;
+//	int Shadow;
+//};
+//
+//typedef struct _tnsCssMisc tnsCssMisc;
+//struct _tnsCssMisc{
+//	real       Color[4];
+//	int         Size;
+//	const char * Name;
+//	const char * Description;
+//};
+//
+//typedef struct _tnsCssState tnsCssState;
+//struct _tnsCssState{
+//	char             NameReplace[36];
+//	tnsCssBackground Bkg;
+//	tnsCssBorder	 BorderLeft;
+//	tnsCssBorder	 BorderRight;
+//	tnsCssBorder	 BorderTop;
+//	tnsCssBorder	 BorderBottom;
+//	tnsCssText       Text;
+//	tnsCssMisc       Misc1;
+//	tnsCssMisc       Misc2;
+//	tnsCssMisc       Misc3;
+//	tnsCssMisc       Misc4;
+//};
+
+#define TNS_STATE_NORMAL 0
+#define TNS_STATE_PUSHED 1
+#define TNS_STATE_HIGHLIGHT 2
+#define TNS_STATE_HIGHLIGHT_SELECT 3
+#define TNS_STATE_KEYING 4
+#define TNS_STATE_INTERPOLATING 5
+#define TNS_STATE_LIMITED 6
+//
+//typedef struct _tnsCssStyle tnsCssStyle;
+//struct _tnsCssStyle{
+//	tnsCssState Normal;
+//	tnsCssState Pushed;
+//	tnsCssState Highlight;
+//	tnsCssState HighlightSelect;
+//	tnsCssState Keying;
+//	tnsCssState Interpolating;
+//	tnsCssState Limited;
+//};
+
+//=====================================================[3d comp]
+
+typedef struct _tnsWorld tnsWorld;
+typedef struct _tnsObject tnsObject;
+
+#define TNS_ROTATION_XYZ_EULER 0
+#define TNS_ROTATION_XZY_EULER 1
+#define TNS_ROTATION_YXZ_EULER 2
+#define TNS_ROTATION_YZX_EULER 3
+#define TNS_ROTATION_ZXY_EULER 4
+#define TNS_ROTATION_ZYX_EULER 5
+#define TNS_ROTATION_QUATERNION 6
+
+#define TNS_OBJECT_ROOT   0
+#define TNS_OBJECT_EMPTY  (1<<0)
+#define TNS_OBJECT_CAMERA (1<<1)
+#define TNS_OBJECT_LIGHT  (1<<2)
+#define TNS_OBJECT_MESH   (1<<3)
+
+//typedef struct _tnsObjectLinker tnsObjectLinker;
+//struct _tnsObjectLinker {
+//	laListItem    Item;
+//	tnsObject* o;
+//};
+
+NEED_STRUCTURE(tnsRenderTriangle);
+NEED_STRUCTURE(tnsRenderVert);
+
+#define TNS_OBJECT_FLAGS_SELECTED 1
+
+typedef struct _tnsObject tnsObject;
+struct _tnsObject
+{
+    laListItem Item;
+
+    int Type;
+    int SelectID;
+    int Flags;
+    //u64bit ID;
+    laSafeString *Name;
+    int DrawMode;
+
+    int Show;
+    int ShowOnRender;
+    int HideChildren;
+
+    real GLocation[3];
+    real GRotation[3];
+    real GScale;
+
+    real Location[3];
+    real Rotation[4];
+    real Scale;//Only allow uniform scale
+    u8bit RotationMode;
+
+    tnsMatrix44d GlobalTransform;
+    tnsMatrix44d SelfTransform;
+    //tnsMatrix44d CameraTransform;
+
+    tnsObject *InRoot;
+    tnsObject *ParentObject;   // reused as root active sun.
+    laListHandle ChildObjects;
+};
+
+#define TNS_PRESPECTIVE_CAMERA 0
+#define TNS_ORTHOGRAPHICAL_CAMERA 1
+#define TNS_FISHEYE_CAMERA 2
+
+NEED_STRUCTURE(tnsBatch)
+
+#define TNS_MATERIAL_DRAW_MODE_SOLID 0
+#define TNS_MATERIAL_DRAW_MODE_WIRE 1
+
+typedef struct _tnsMaterial tnsMaterial;
+struct _tnsMaterial
+{
+    laListItem Item;
+
+    laSafeString *Name;
+
+    int ID;
+
+    int DrawMode;
+
+    real Color[4];
+    real LinearColor[4];
+    real SpectacularColor[4];
+    real ReflexThreshold;
+    real ReflexStrengh;
+    real ReflexSharpeness;
+
+    real LowBrightnessColor[4]; //Windows are lighten up in the evenings
+    u8bit HaloMode;
+};
+
+#define TNS_CAMERA_PERSPECTIVE 0
+#define TNS_CAMERA_ORTHO 1
+#define TNS_CAMERA_FISHEYE 2
+
+typedef struct _tnsCamera tnsCamera;
+struct _tnsCamera
+{
+    tnsObject Base;
+
+    int CameraType;
+    real FOV;
+    real ZMin, ZMax;
+    real FocusDistance;
+
+    real OrthScale;
+    tnsVector3d RenderViewDir;
+};
+
+typedef struct _tnsLight tnsLight;
+struct _tnsLight
+{
+    tnsObject Base;
+
+    int LightType;
+    int UniDirectional;
+    real Strength;
+
+    tnsMaterial *Material;
+};
+
+STRUCTURE(tnsGroup){
+    laListItem Item;
+
+    laListHandle ObjectLinks;
+
+    laSafeString *Name;
+
+    tnsVector4d Color1;
+    tnsVector4d Color2;
+
+    int ExcludeFromCalculation;
+};
+
+#define TNS_MESH_FLAG_SELECTED 1
+
+STRUCTURE(tnsMVert){
+    laListItem Item;
+    tnsVector3d p;
+    tnsVector3d n;
+    int flags;
+    u32bit i;
+    laListHandle elink;
+    //laListHandle flink;
+};
+NEED_STRUCTURE(tnsMFace);
+STRUCTURE(tnsMEdge){
+    laListItem Item;
+    tnsMVert *vl;
+    tnsMVert *vr;
+    tnsMFace *fl;
+    tnsMFace *fr;
+    u32bit i;
+    int flags;
+};
+STRUCTURE(tnsMFace){
+    laListItem Item;
+    laListHandle l; //list item pointer of edges
+    tnsVector3d n;
+    tnsVector3d gn;
+    tnsVector3d c;
+    short looplen;
+    short mat;
+    u32bit i;
+    int flags;
+};
+
+STRUCTURE(tnsVert){
+    tnsVector3f p;
+    int flags;
+};
+STRUCTURE(tnsEdge){
+    int l,r;
+    int flags;
+};
+STRUCTURE(tnsFace){
+    int* loop;
+    short looplen;
+    int flags;
+};
+
+STRUCTURE(tnsBatchCommand){
+    laListItem Item;
+    char* name;
+    int DrawElements;
+    GLuint EBO; //elem
+    u32bit ElementCount;
+    GLenum DrawAs;
+    int UseUniformColor; real UniformColor[4];
+    GLuint CBO; int ColorDimension; int OverrideColorArray;
+    int Dimension;
+    int HiddenByDefault;
+};
+STRUCTURE(tnsBatch){
+    laListItem Item;
+    GLuint VBO; //vert
+    GLuint NBO; int HasNormal; //normal
+    GLuint CBO; int HasColor; //color
+    u32bit NumVert;
+    int Dimension;
+    int NormalDimension;
+    int ColorDimension;
+    laListHandle Branches;
+    GLuint BeginElementOffset;
+};
+
+#define TNS_MESH_OBJECT_MODE 0
+#define TNS_MESH_EDIT_MODE   1
+
+extern laPropContainer* TNS_PC_OBJECT_GENERIC;
+extern laPropContainer* TNS_PC_OBJECT_CAMERA;
+extern laPropContainer* TNS_PC_OBJECT_LIGHT;
+extern laPropContainer* TNS_PC_OBJECT_MESH;
+
+#define TNS_HINT_TRANSFORM (1<<1)
+#define TNS_HINT_GEOMETRY  (1<<0)
+
+STRUCTURE(tnsMeshFaceStorageSingleHead){
+    int looplen, flags; //[1] [5] [4] [2] ... [-1 as end]
+};
+STRUCTURE(tnsMeshFaceStorage){
+    int len; int arr;
+};
+
+STRUCTURE(tnsMeshObject){
+    tnsObject Base;
+
+    tnsVert* v; int totv, maxv;
+    tnsEdge* e; int tote, maxe; // I intend this to only stores floating edges.
+    tnsFace* f; int totf, maxf;
+
+    laListHandle mv; int totmv;
+    laListHandle me; int totme;
+    laListHandle mf; int totmf;
+
+    int TriangleCount;
+    int TriangulatedEdgeCount;
+    
+    tnsBatch *Batch;
+
+    int Mode;
+};
+
+STRUCTURE(tnsEdgeHashEdge){
+    int tv; tnsMEdge* me;
+};
+STRUCTURE(tnsEdgeHashVert){
+    tnsEdgeHashEdge* e; int max, next; tnsMVert* mv;
+};
+STRUCTURE(tnsEdgeHash){
+    tnsEdgeHashVert* vl; int max,next;
+};
+
+#define TNS_TILE(tile, r, c, CCount) \
+    tile[r * CCount + c]
+
+#define TNS_CLAMP(a, Min, Max) \
+    a = a < Min ? Min : (a > Max ? Max : a)
+
+#define TNS_MAX2(a, b) \
+    (a > b ? a : b)
+
+#define TNS_MIN2(a, b) \
+    (a < b ? a : b)
+
+#define TNS_MAX3(a, b, c) \
+    (a > TNS_MAX2(b, c) ? a : TNS_MAX2(b, c))
+
+#define TNS_MIN3(a, b, c) \
+    (a < TNS_MIN2(b, c) ? a : TNS_MIN2(b, c))
+
+#define TNS_MAX2_INDEX(a, b) \
+    (a > b ? 0 : 1)
+
+#define TNS_MIN2_INDEX(a, b) \
+    (a < b ? 0 : 1)
+
+#define TNS_MAX3_INDEX(a, b, c) \
+    (a > b ? (a > c ? 0 : (b > c ? 1 : 2)) : (b > c ? 1 : 2))
+
+#define TNS_MIN3_INDEX(a, b, c) \
+    (a < b ? (a < c ? 0 : (b < c ? 1 : 2)) : (b < c ? 1 : 2))
+
+#define TNS_MAX3_INDEX_ABC(x, y, z) \
+    (x > y ? (x > z ? a : (y > z ? b : c)) : (y > z ? b : c))
+
+#define TNS_MIN3_INDEX_ABC(x, y, z) \
+    (x < y ? (x < z ? a : (y < z ? b : c)) : (y < z ? b : c))
+
+#define TNS_ABC(index) \
+    (index == 0 ? a : (index == 1 ? b : c))
+
+#define TNS_DOUBLE_CLOSE_ENOUGH(a, b) \
+    (((a) + DBL_EDGE_LIM) >= (b) && ((a)-DBL_EDGE_LIM) <= (b))
+
+    //#define TNS_DOUBLE_CLOSE_ENOUGH(a,b)\
+//(((a)+0.00000000001)>=(b) && ((a)-0.0000000001)<=(b))
+
+#define TNS_FLOAT_CLOSE_ENOUGH_WIDER(a, b) \
+    (((a) + 0.0000001) >= (b) && ((a)-0.0000001) <= (b))
+
+#define TNS_FRAMEBUFFER_PIXEL(FrameBuffer, Row, Column) \
+    &((FrameBuffer)->Pixels[Row * FrameBuffer->TileSizeW * FrameBuffer->W * FrameBuffer->SubPixelSample + Column * FrameBuffer->H * FrameBuffer->TileSizeH * FrameBuffer->SubPixelSample])
+
+#define TNS_IN_TILE_X(RenderTile, Fx) \
+    (RenderTile->FX <= Fx && RenderTile->FXLim >= Fx)
+
+#define TNS_IN_TILE_Y(RenderTile, Fy) \
+    (RenderTile->FY <= Fy && RenderTile->FYLim >= Fy)
+
+#define TNS_IN_TILE(RenderTile, Fx, Fy) \
+    (TNS_IN_TILE_X(RenderTile, Fx) && TNS_IN_TILE_Y(RenderTile, Fy))
+
+#define TNS_RENDERBUFFER_INCOMPLETE 0
+#define TNS_RENDERBUFFER_GEOMETRY_COMPLETE 1
+#define TNS_RENDERBUFFER_RASTERIZER_COMPLETE 2
+#define TNS_RENDERBUFFER_COMPLETE (TNS_RENDERBUFFER_GEOMETRY_COMPLETE | TNS_RENDERBUFFER_RASTERIZER_COMPLETE)
+
+#define TNS_DISPLAY_MODE_WIRE GL_LINE_LOOP
+#define TNS_DISPLAY_MODE_SOLID GL_TRIANGLES
+#define TNS_INTERNAL_MODE_WIRE 1
+#define TNS_INTERNAL_MODE_SOLID 2
+
+#define TNS_ARROW_L 1
+#define TNS_ARROW_R 2
+#define TNS_ARROW_U 3
+#define TNS_ARROW_D 4
+
+#define TNS_KEYWORD_OBJECT_COUNT 1
+#define TNS_KEYWORD_OBJECT_NAME 2
+#define TNS_KEYWORD_OBJECT_TYPE 3
+#define TNS_KEYWORD_OBJECT_LOCATION 4
+#define TNS_KEYWORD_OBJECT_ROTATION 5
+#define TNS_KEYWORD_OBJECT_SCALE 6
+#define TNS_KEYWORD_OBJECT_CHILDREN_COUNT 7
+#define TNS_KEYWORD_OBJECT_CHILDREN_NAMES 8
+//#define TNS_KEYWORD_MESH_COUNT            9
+//#define TNS_KEYWORD_MESH_NAME             10
+#define TNS_KEYWORD_MESH_VERTEX_COUNT 11
+#define TNS_KEYWORD_MESH_VERTICES 12
+#define TNS_KEYWORD_MESH_LOOP_COUNT 13
+#define TNS_KEYWORD_MESH_TOPOLOGY 14
+#define TNS_KEYWORD_MESH_UV_COUNT 15
+#define TNS_KEYWORD_MESH_UV_NAME 16
+#define TNS_KEYWORD_MATERIAL_COUNT 17
+#define TNS_KEYWORD_MATERIAL_NAME 18
+#define TNS_KEYWORD_MATERIAL_COLOR 19
+#define TNS_KEYWORD_MATERIAL_END 20
+
+#define TNS_KEYWORD_CAMERA_FOV 20
+#define TNS_KEYWORD_CAMERA_IS_ACTIVE 21
+#define TNS_KEYWORD_CAMERA_NEAR 22
+#define TNS_KEYWORD_CAMERA_FAR 23
+
+#define TNS_KEYWORD_GROUP_COUNT 24
+#define TNS_KEYWORD_GROUP_NAME 25
+#define TNS_KEYWORD_OBJECT_GROUP_COUNT 26
+
+void tnsSetuptnsFontManager();
+
+tnsShader *tnsNewShaderProgram(int VertexShaderID, int FragmentShaderID, int GeometryShaderID);
+int tnsNewFragmentShader(char *Content);
+int tnsNewVertexShader(char *Content);
+void tnsDeleteShaderProgram(tnsShader* s);
+
+int tnsNextPowOf2(int i);
+
+int tnsEnableShader(int index);
+int tnsEnableShaderv(tnsShader *shader);
+int tnsUseShader(tnsShader *shader);
+void tnsUseImmShader();
+void tnsUseShadowShader();
+void tnsUseSceneShader();
+void tnsUseRayShader();
+void tnsUseTransparentGridShader();
+
+void tnsUseImagePeelShader();
+
+void tnsInitRenderKernel(int matrixStackLevel);
+void tnsInitBuiltinShaders();
+void tnsInitWindowDefaultRenderConfig();
+void tnsQuit();
+
+real *tnsGetModelMatrix();
+real *tnsGetViewMatrix();
+real *tnsGetProjectionMatrix();
+void tnsGetMVMatrix(tnsMatrix44d r);
+void tnsGetMVPMatrix(tnsMatrix44d r);
+void tnsResetModelMatrix();
+void tnsResetViewMatrix();
+void tnsResetProjectionMatrix();
+
+void tnsOrtho(real xMin, real xMax, real yMin, real yMax, real zMin, real zMax);
+void tnsPerspective(real fFov_rad, real fAspect, real zMin, real zMax);
+
+void tnsPopMatrix();
+void tnsPushMatrix();
+
+void tnsTranslate3d(real x, real y, real z);
+void tnsPreTranslate3d(real x, real y, real z);
+void tnsRotate4d(real degrees, real x, real y, real z);
+void tnsPreRotate4d(real degrees, real x, real y, real z);
+void tnsScale3d(real x, real y, real z);
+void tnsPreScale3d(real x, real y, real z);
+
+void tnsColor4d(real r, real g, real b, real a);
+void tnsColor4dv(real *rgba);
+
+void tnsPolygonMode(GLenum PolyMode);
+void tnsShadeMode(GLenum ShadeMode);
+
+tnsBatch *tnsCreateBatch(u32bit NumVert, int Dimension, float *Data, int NormalDimension, float *Normal, int ColorDimension, float *Colors);
+tnsBatch *tnsCreateBatchi(u32bit NumVert, int Dimension, int *Data);
+void tnsCommandUseUniformColor(tnsBatchCommand*c,real* color);
+void tnsCommandOverrideColorArray(tnsBatchCommand*c, int VertCount, int ColorDimension, float* colors);
+tnsBatchCommand *tnsCreateCommand(tnsBatch *b, const char* name, u32bit ElementCount, int Dimension, GLenum DrawAs, u32bit *Elements, int HiddenByDefault);
+void tnsDeleteBatch(tnsBatch *b);
+void tnsDrawBatch(tnsBatch* batch, const char* OverrideCommand, real* OverrideUniformColor, int OverrideAsArray);
+
+void tnsVertex3d(real x, real y, real z);
+void tnsVertex2d(real x, real y);
+void tnsVertexArray2d(real *verts, int amount);
+void tnsVertexArray3d(real *verts, int amount);
+void tnsColorArray4d(real *colors, int amount);
+void tnsNormalArray3d(real *normals, int amount);
+void tnsTexCoordArray2d(real *coords, int amount);
+void tnsTexCoordArray3d(real *coords, int amount);
+void tnsIndexArray(GLuint *index, short amount);
+void tnsPackAs(GLenum Mode);
+void tnsFlush();
+
+#define tnsLinearItp(L, R, T) \
+    ((L) * (1.0f - (T)) + (R) * (T))
+
+double tnsGetRatiod(real L, real R, real FromL);
+
+void tnsShaderApplyProjectionInverse(tnsShader *tns, tnsMatrix44d m);
+void tnsShaderApplyProjection(tnsShader *tns, tnsMatrix44d m);
+void tnsShaderApplyModel(tnsShader *tns, tnsMatrix44d m);
+void tnsShaderApplyView(tnsShader *tns, tnsMatrix44d m);
+void tnsShaderApplyNormalScaler(tnsShader *tns, tnsMatrix44d m);
+
+
+int tnsLineIntersectTest2d(tnsVector2d a1, tnsVector2d a2, tnsVector2d b1, tnsVector2d b2, double *aRatio);
+double tnsGetLineZ(tnsVector3d L, tnsVector3d R, real Ratio);
+double tnsGetLineZPoint(tnsVector3d L, tnsVector3d R, tnsVector3d FromL);
+double tnsGetRatio3d(tnsVector3d L, tnsVector3d R, tnsVector3d FromL);
+double tnsGetRatiod(real L, real R, real FromL);
+void tnsInterpolateTripple2d(tnsVector2d v1, tnsVector2d v2, tnsVector2d v3, real ratio, tnsVector2d result);
+void tnsVectorMinus2d(tnsVector2d result, tnsVector2d l, tnsVector2d r);
+void tnsVectorMinus3d(tnsVector3d result, tnsVector3d l, tnsVector3d r);
+void tnsVectorSubtract3d(tnsVector3d l, tnsVector3d r);
+void tnsVectorPlus3d(tnsVector3d result, tnsVector3d l, tnsVector3d r);
+void tnsVectorAccum3d(tnsVector3d l, tnsVector3d r);
+void tnsVectorAccum2d(tnsVector2d l, tnsVector2d r);
+void tnsVectorNegate3d(tnsVector3d result, tnsVector3d l);
+void tnsVectorNegateSelf3d(tnsVector3d l);
+void tnsVectorCopy2d(tnsVector2d from, tnsVector2d to);
+void tnsVectorCopy3d(tnsVector3d from, tnsVector3d to);
+void tnsVectorCopy4d(tnsVector4d from, tnsVector4d to);
+void tnsVectorMultiSelf4d(tnsVector4d from, real num);
+void tnsVectorMultiSelf3d(tnsVector3d from, real num);
+void tnsVectorMultiSelf2d(tnsVector3d from, real num);
+void tnsVectorMulti4d(tnsVector4d to, tnsVector4d from, real num);
+void tnsVectorMulti3d(tnsVector3d to, tnsVector3d from, real num);
+void tnsVectorMulti2d(tnsVector2d to, tnsVector2d from, real num);
+real tnsDirectionToRad(tnsVector2d Dir);
+void tnsConvert44df(tnsMatrix44d from, tnsMatrix44f to);
+int tnsTrangleLineBoundBoxTest(tnsRenderTriangle *rt, tnsRenderLine *rl);
+
+
+real tnsDistIdv2(real x1, real y1, real x2, real y2);
+real tnsDist3dv(tnsVector3d l, tnsVector3d r);
+real tnsDist2dv(tnsVector2d l, tnsVector2d r);
+
+real tnsLength3d(tnsVector3d l);
+real tnsLength2d(tnsVector3d l);
+void tnsNormalize3d(tnsVector3d result, tnsVector3d l);
+void tnsNormalizeSelf2d(tnsVector3d result);
+void tnsNormalizeSelf3d(tnsVector3d result);
+real tnsDot3d(tnsVector3d l, tnsVector3d r, int normalize);
+real tnsDot2d(tnsVector2d l, tnsVector2d r, int normalize);
+real tnsVectorCross3d(tnsVector3d result, tnsVector3d l, tnsVector3d r);
+real tnsAngleRad3d(tnsVector3d from, tnsVector3d to, tnsVector3d PositiveReference);
+void tnsApplyRotation33d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v);
+void tnsApplyRotation43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v);
+void tnsApplyTransform43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v);
+void tnsApplyNormalTransform43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v);
+void tnsApplyTransform44d(tnsVector4d result, tnsMatrix44d mat, tnsVector4d v);
+void tnsApplyTransform44dTrue(tnsVector4d result, tnsMatrix44d mat, tnsVector4d v);
+
+void tnsLoadIdentity44d(tnsMatrix44d m);
+void tnsMakeOrthoMatrix44d(tnsMatrix44d mProjection, real xMin, real xMax, real yMin, real yMax, real zMin, real zMax);
+void tnsMakePerspectiveMatrix44d(tnsMatrix44d mProjection, real fFov_rad, real fAspect, real zMin, real zMax);
+void tnsMakeTranslationMatrix44d(tnsMatrix44d mTrans, real x, real y, real z);
+void tnsMakeRotationMatrix44d(tnsMatrix44d m, real angle_rad, real x, real y, real z);
+void tnsMakeScaleMatrix44d(tnsMatrix44d m, real x, real y, real z);
+void tnsMakeViewportMatrix44d(tnsMatrix44d m, real w, real h, real Far, real Near);
+void tnsMultiply44d(tnsMatrix44d result, tnsMatrix44d l, tnsMatrix44d r);
+void tnsMakeRotationXMatrix44d(tnsMatrix44d m, real angle_rad);
+void tnsMakeRotationYMatrix44d(tnsMatrix44d m, real angle_rad);
+void tnsMakeRotationZMatrix44d(tnsMatrix44d m, real angle_rad);
+void tnsRemoveTranslation44d(tnsMatrix44d result, tnsMatrix44d mat);
+void tnsClearTranslation44d(tnsMatrix44d mat);
+
+real tnsAngleRad3d(tnsVector3d from, tnsVector3d to, tnsVector3d PositiveReference);
+real tnsLength3d(tnsVector3d l);
+void tnsNormalize2d(tnsVector2d result, tnsVector2d l);
+void tnsNormalize3d(tnsVector3d result, tnsVector3d l);
+void tnsNormalizeSelf3d(tnsVector3d result);
+real tnsDot3d(tnsVector3d l, tnsVector3d r, int normalize);
+real tnsVectorCross3d(tnsVector3d result, tnsVector3d l, tnsVector3d r);
+void tnsVectorCrossOnly3d(tnsVector3d result, tnsVector3d l, tnsVector3d r);
+
+void tnsExtractXYZEuler44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result);
+
+void tnsPrintMatrix44d(tnsMatrix44d l);
+
+int tnsPointInsideTriangle3d(tnsVector3d v, tnsVector3d v0, tnsVector3d v1, tnsVector3d v2);
+
+void tnsExtractXYZEuler44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result);
+void tnsExtractLocation44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result);
+void tnsExtractUniformScale44d(tnsMatrix44d mat, real *result);
+void tnsSelfMatrixChanged(tnsObject* o, int ApplyToChild);
+void tnsGlobalMatrixChanged(tnsObject* o, int ApplyToChild);
+void tnsSelfTransformValueChanged(tnsObject* o);
+void tnsGlobalTransformValueChanged(tnsObject* o);
+
+void tnsSetCurrentRoot(tnsObject *o);
+void tnsInitObjectBase(tnsObject *o, tnsObject *under, char *Name, int Type,
+                        real AtX, real AtY, real AtZ,
+                        real RotX, real RotY, real RotZ, real RotW, u8bit RotationMode,
+                        real Scale);
+
+tnsMeshObject *tnsLoadObjectFromFile(char *FileName);
+
+int tnsLoadExchange(char *FileName);
+
+tnsObject *tnsFindObject(char *Name, tnsObject *From);
+
+void tnsRotateObjectGlobal(tnsObject *o, real x, real y, real z, real angle, real cx,real cy,real cz);
+void tnsRotateObjectLocal(tnsObject *o, real x, real y, real z, real angle, real gcx,real gcy,real gcz);
+void tnsRotateObjectLocalValues(tnsObject *o, real x, real y, real z);
+void tnsTranslateObjectGlobal(tnsObject *o, real x, real y, real z);
+void tnsTranslateObjectLocal(tnsObject *o, real x, real y, real z);
+void tnsMoveObjectLocal(tnsObject *o, real x, real y, real z);
+void tnsMoveObjectGlobal(tnsObject *o, real x, real y, real z);
+void tnsScaleObject(tnsObject *o, real fac, real cx,real cy,real cz);
+int tnsCheckParentable(tnsObject* child, tnsObject* parent);
+void tnsParentObject(tnsObject *child, tnsObject *parent, int KeepTransform);
+void tnsUnparentObject(tnsObject *o, int KeepTransform);
+void tnsZoomViewingCamera(tnsCamera *c, real Ratio);
+void tnsRotateViewingCamera(tnsCamera *c, real x, real z);
+void tnsTranslateViewingCamera(tnsCamera *c, int ViewportW, int ViewportH, real x, real y);
+
+void tnsGetCameraMovingDeltas(tnsCamera *c, int ViewportW, int ViewportH, real x, real y, tnsVector4d p);
+
+laPropContainer* tnsget_ObjectType(tnsObject* o);
+
+void tnsDestroyRootObject(tnsObject *root);
+void tnsDestroyObject(tnsObject *o);
+
+tnsObject *tnsCreateRootObject(char *name);
+tnsCamera *tnsCreateCamera(tnsObject *under, char *Name, real FOV,
+                              real AtX, real AtY, real AtZ,
+                              real RotX, real RotY, real RotZ,
+                              real FocusDistance);
+tnsObject *tnsCreateEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ);
+tnsLight *tnsCreateLight(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real Strength, int UniDirectional);
+tnsMeshObject *tnsCreateMeshPlane(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size);
+
+int tnsAnyObjectsSelected(tnsObject* parent);
+void tnsDeselectAllObjects(tnsObject* parent);
+void tnsSelectAllObjects(tnsObject* parent);
+void tnsSelectObject(tnsObject* o, int Select, int Toggle);
+
+tnsMFace* tnsMMeshNewFace(tnsMeshObject* mo);
+tnsMEdge* tnsMMeshNewEdge(tnsMeshObject* mo);
+tnsMVert* tnsMMeshNewVert(tnsMeshObject* mo);
+void tnsMMeshEdgeAssignVerts(tnsMEdge* me,tnsMVert* mv1,tnsMVert* mv2);
+tnsMVert* tnsMMeshEdgeShareVert(tnsMEdge* me0, tnsMEdge* me1);
+tnsMVert* tnsMMeshEdgeAnotherVert(tnsMEdge* me, tnsVert* v);
+tnsMVert* tnsMMeshEdgeStartingVert(tnsMEdge* me0, tnsMEdge* me1);
+int tnsMMeshSplitFace(tnsMeshObject* mo, tnsMFace* mf, tnsMEdge* me, tnsMFace** r_f1, tnsMFace** r_f2);
+void tnsMMeshFaceAddEdge(tnsMFace* mf, tnsMEdge* me);
+int tnsMMeshFaceMatches(tnsMFace* mf, int ecount, ...);
+tnsMFace* tnsMMeshMakeFace4v(tnsMeshObject* mo, tnsVert* v1,tnsVert* v2,tnsVert* v3,tnsVert* v4);
+void tnsMMeshRemoveFaceOnly(tnsMeshObject* mo, tnsMFace* mf);
+void tnsMMeshRemoveEdgeFace(tnsMeshObject* mo, tnsMEdge* me);
+void tnsMMeshRemoveVertEdgeFace(tnsMeshObject* mo, tnsMVert* mv);
+
+void tnsMMeshRefreshIndex(tnsMeshObject* mo);
+
+void tnsMeshEnterEditMode(tnsMeshObject* mo);
+void tnsMeshLeaveEditMode(tnsMeshObject* mo);
+int tnsMMeshAnySelected(tnsMeshObject* mo);
+void tnsMMeshDeselectAll(tnsMeshObject* mo);
+void tnsMMeshSelectAll(tnsMeshObject* mo);
+void tnsMMeshSelectVert(tnsMeshObject* mo, tnsMVert* mv, int select, int toggle);
+void tnsMMeshEnsureSelectionFromVert(tnsMeshObject* mo);
+
+void tnsInvaliateMeshBatch(tnsMeshObject* mo);
+void tnsRegenerateMeshBatch(tnsMeshObject* mo);
+void tnsEnsureMeshBatch(tnsMeshObject* mo);
+void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsSelection, tnsMeshObject* Active);
+
+void la_RegisterModellingOperators();
+
+void tnsGetCameraViewProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera);
+void tnsApplyCameraView(int W, int H, tnsCamera *Camera);
+void tnsApplyShadowCameraView(tnsLight *Light);
+
+void tnsApplyObjectMatrix(tnsObject *Object);
+
+void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up);
+
+void tnsDrawThisObject(tnsObject *o, tnsObject *active, int DrawAsSelection);
+void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsSelection);
+void tnsDrawScene(int W, int H, tnsObject *root);
+void tnsDrawWorld(int W, int H);
+
+tnsMaterial *tnsCreateMaterial(char *Name);
+tnsMaterial *tnsFindMaterialByIndex(int index);
+tnsMaterial *tnsFindMaterial(char *name);
+
+void tnsClearAll();
+void tnsClearColorv(real *rgba);
+void tnsClearColor(real r, real g, real b, real a);
+void tnsSwitchToCurrentWindowContext(void *wnd);
+
+void tnsRecalculateVertNormal(tnsVert *v);
+void tnsRecalculateFaceAverageNormal(tnsFace *f);
+
+int tnsLoadVectorGraphPackage(const char *name, unsigned int size);
+int tnsGetMonoFontAdvance();
+int tnsInvalidateFontCache();
+void tnsLoadSystemFontMono(char* mono);
+void tnsLoadSystemFont(int num_fonts, ...);
+int tnsGetTextureMemoryComponetCount(tnsTexture *t);
+
+int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Multisample);
+tnsTexture *tnsCreate2DTexture(GLint glInternalFormat, int w, int h, int Multisample);
+void tnsConfigureTexture(tnsTexture *t);
+void tnsReconfigureTextureParameters(int Multisample);
+tnsOffscreen *tnsCreate2DOffscreen(int glInternalFormat, int w, int h, int Multisample, int WithDepth);
+void tnsCopyScreenTo2DTexture(tnsTexture *target, int x_lower_left, int y_lower_left, int w, int h);
+void tnsActiveTexture(GLenum tex);
+void tnsBindTexture(tnsTexture *t);
+void tnsUnbindTexture();
+void tnsUniformUseTexture(tnsShader* s, int mode, int sample);
+void tnsUniformUseMultiplyColor(tnsShader* s, int enable);
+void tnsUseMaskTexture(tnsTexture *t);
+void tnsUseTexture(tnsTexture *t);
+void tnsUseNoTexture();
+void tnsUseMultiplyColor(int enable);
+void tnsDeleteTexture(tnsTexture *t);
+void tnsDraw2DTextureDirectly(tnsTexture *t, real x, real y, real w, real h);
+void tnsDraw2DTextureArg(tnsTexture *t,
+                         real x_upper_right, real y_upper_right, int w, int h,
+                         real *MultiplyColor,
+                         real LPadding, real RPadding, real TPadding, real BPadding);
+
+int tnsTextureMemorySize(tnsTexture *t, int mem);
+void tnsCreateTextureReadbackBuffer(tnsTexture *t);
+void tnsDeleteTextureReadbackBuffer(tnsTexture *t);
+void tnsReadbackTexture(tnsTexture *t);
+
+#define TNS_CLAMP_TEXTURE_W(t, Col) \
+    {                               \
+        if (Col >= t->Width)        \
+            Col = t->Width - 1;     \
+        if (Col < 0)                \
+            Col = 0;                \
+    }
+
+#define TNS_CLAMP_TEXTURE_H(t, Row) \
+    {                               \
+        if (Row >= t->Height)       \
+            Row = t->Height - 1;    \
+        if (Row < 0)                \
+            Row = 0;                \
+    }
+
+#define TNS_CLAMP_TEXTURE_CONTINUE(t, Col, Row) \
+    {                                           \
+        if (Col >= t->Width)                    \
+            continue;                           \
+        if (Col < 0)                            \
+            continue;                           \
+        if (Row >= t->Height)                   \
+            continue;                           \
+        if (Row < 0)                            \
+            continue;                           \
+    }
+
+void tnsDelete2DOffscreen(tnsOffscreen *o);
+tnsOffscreen *tnsCreateOffscreenHandle();
+void tnsConfigureOffscreen(tnsOffscreen *off, int w, int h);
+void tnsAttach2DOffscreenBuffer(tnsOffscreen *target, GLuint attatchment, tnsTexture *use);
+void tnsDetach2DOffscreenBuffer(tnsOffscreen *target, GLuint which_attach_point);
+
+void tnsDrawToOffscreen(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray);
+void tnsDrawToExtraColorAttachment(tnsOffscreen *toff);
+void tnsDrawToExtraNormalAttachment(tnsOffscreen *toff);
+void tnsDrawToAllExtraAttachments(tnsOffscreen *toff);
+void tnsDrawToOffscreenOnlyBind(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray);
+void tnsReadFromOffscreen(tnsOffscreen *toff);
+void tnsPassColorBetweenOffscreens(tnsOffscreen *from, tnsOffscreen *to,
+                                   GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLenum FilterMode);
+
+void tnsDrawToScreen();
+
+//==============================================[STR]
+
+int tnsUseFont(char *name);
+int laStopFontService();
+
+tnsFontSingleCharacter *tfntFetchVectorGraphTextureIDW(uint32_t ID);
+
+int tnsStringGetDimension(char* content, uint32_t* contentU, int Count, int WLimit, int* Rows, int UseMono);
+int tnsStringGetWidth(char *content, int Count, int UseMono);
+int tnsStringGetWidthU(uint32_t *contentU, int Count, int UseMono);
+void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags);
+void tnsDrawStringAutoM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags);
+void tnsDrawStringAuto(char *content, real Color[4], int L, int R, int T, int Flags);
+void tnsDrawStringWithPriority(char *Label, char *MajorContent, real Color[4], int TextAlign, int L, int R, int T, int Flags);
+void tnsDrawVectorGraphPackage(int ID, real Color[4], int L, int R, int T, int B, int Align, int Flags);
+void tnsDrawIcon(uint32_t ID, real Color[4], int L,int R, int T, int Flags);
+
+void tnsUseFontCoord(real x, real y, real size);
+
+///=================================
+
+void tnsMakeTriangle(real *arr, real x1, real y1, real x2, real y2, real x3, real y3);
+void tnsMakeQuad2d(real *arr, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4);
+void tnsMakeQuadT2d(real *arr, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4);
+void tnsMakeQuad3d(real *arr, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4);
+void tnsMakeQuad4d(real *arr, real x1, real y1, real z1, real w1, real x2, real y2, real z2, real w2, real x3, real y3, real z3, real w3, real x4, real y4, real z4, real w4);
+void tnsMakeCircle2d(real *arr, int slices, real ctrX, real ctrY, real r);
+void tnsMakeArc2d(real *arr, int slices, real ctrX, real ctrY, real r, real rad_begin, real rad_end);
+void tnsMakeRing2d(real *arr, int *index, int slices, real ctrX, real ctrY, real r1, real r2);
+
+void tnsMakeLinerGradient3d(real *arr, int num_points, real r0, real g0, real b0, real r1, real g1, real b1);
+void tnsMakeLinerGradient4d(real *arr, int num_points, real r0, real g0, real b0, real a0, real r1, real g1, real b1, real a1);
+void tnsMakeLinerGradient3dv(real *arr, int num_points, real *rgb0, real *rgb1);
+void tnsMakeLinerGradient4dv(real *arr, int num_points, real *rgb0, real *rgb1);
+
+void tnsMakeFoucsSquare(int L, int R, int U, int B, int W);
+void tnsDrawFloor(int Size, int Span, int *ShowAxis);
+
+void tnsMakeIndexUInt(unsigned int *result, int num, ...);
+void tnsMakeBridgedIndex(unsigned int *result, int num, int revert, int begin);
+
+//================================
+
+void DrawWireRect2dp(real x, real y, real x2, real y2);
+void tnsViewportWithScissor(int x, int y, int w, int h);
+
+void tnsSingleLinearToLog(real *a, real gamma);
+void tnsSingleLogToLinear(real *a, real gamma);
+void tnsLinearToLog(real *rgb, real gamma);
+void tnsLogToLinear(real *rgb, real gamma);
+void tnsRgbToLuminance(real *rgb);
+void tnsHCYtoRGB(real *hcy, real *rgb);
+void tnsRGBtoHCY(real *rgb, real *hcy);
+
+tnsLineStrip *tnsCreateLineStrip();
+tnsLineStripPoint *tnsAppendPoint(tnsLineStrip *ls, real X, real Y, real Z);
+tnsLineStripPoint *tnsPushPoint(tnsLineStrip *ls, real X, real Y, real Z);
+void tnsRemovePoint(tnsLineStrip *ls, tnsLineStripPoint *lsp);
+void tnsDestroyLineStrip(tnsLineStrip *ls);
+
+void tnsGetGaussianKernel(tnsFilterKernel *fk, int size, real sigma);
+
+void *tnsTextureSampleSafe(tnsTexture *t, int Col, int Row);
+int tnsTextureSampleWeightSafe(tnsTexture *t, int Col, int Row, real Size, tnsVector2d Direction);
+real tnsTextureSampleSafeGaussU8R(tnsTexture *t, tnsFilterKernel *fk, int Col, int Row);
+void tnsTextureSetBitSafeU8R(tnsTexture *t, int Col, int Row, int Bit);
+void tnsTextureSetRGBSafeU8R(tnsTexture *t, int Col, int Row, u8bit r, u8bit g, u8bit b);
+u8bit *tnsTextureSampleU8(tnsTexture *t, int Col, int Row);

+ 116 - 0
source/lagui/la_tns_curve.c

@@ -0,0 +1,116 @@
+#include "la_5.h"
+
+/*
+NUL4.0 - Nick's Best - www.nicksbest.com
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@  TNS OpenGL 2D/3D Rendering System  @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@                  __                 @@
+@@            ___---  |                @@
+@@      __----     @@  ||              @@
+@@  _---  _         @@@  ||            @@
+@@   |  @@@__         @@   ||          @@
+@@    |  @@ #@@@#_     @@@   ||        @@
+@@     |  @@     `#@@@@  @@    |_      @@
+@@      |  @@         `#@@@@@_--       @@
+@@       |  @@          _--'           @@
+@@        |  @@     _---               @@
+@@         |  @@_---                   @@
+@@          |_--          _ __ __ __ __@@
+@@                       |  Not Fancy  @@
+@@                       |  But Easy   @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+Author(s):WuYiming - xp8110@outlook.com
+
+Want to join the development?
+Append your name in the author list above.
+Send feedback to la_support@nicksbest.com
+*/
+#include "la_tns.h"
+
+#include "la_util.h"
+#include <math.h>
+
+extern tnsMain *T;
+
+real tnsInterpolate(real L, real R, real T){
+    return tnsLinearItp(L, R, T);
+}
+void tnsInterpolate2dv(real *L, real *R, real T, real *Result){
+    Result[0] = tnsLinearItp(L[0], R[0], T);
+    Result[1] = tnsLinearItp(L[1], R[1], T);
+}
+void tnsInterpolate3dv(real *L, real *R, real T, real *Result){
+    Result[0] = tnsLinearItp(L[0], R[0], T);
+    Result[1] = tnsLinearItp(L[1], R[1], T);
+    Result[2] = tnsLinearItp(L[2], R[2], T);
+}
+
+//z3 = 1/( linearintp(1/z1),(1/z2),t )
+//L,R is GLocation
+void tnsInterpolatePerspective4dv(tnsVector4d LG, tnsVector4d RG, tnsVector4d L, tnsVector4d R, real T, tnsVector3d Result){
+    ////real t = (w - L[3]) / (R[3] - L[3]);
+    real z = 1 / tnsLinearItp(1 / L[2], 1 / R[2], T);
+
+    ////Result[2] = tnsLinearItp(L[2] / L[3], R[2] / R[3], t)*w;
+    ////Result[0] = tnsLinearItp(L[0] / L[3], R[0] / R[3], t)*w;
+    ////Result[1] = tnsLinearItp(L[1] / L[3], R[1] / R[3], t)*w;
+
+    Result[0] = tnsLinearItp(L[0] / L[2], R[0] / R[2], T) * z;
+    Result[1] = tnsLinearItp(L[1] / L[2], R[1] / R[2], T) * z;
+    Result[2] = z;
+
+    //real x1z1 = LG[0] / LG[2], x2z2 = RG[0] / RG[2];
+    //real x3 = tnsLinearItp(LG[0], RG[0], T);
+    //real z3 = tnsLinearItp(LG[2], RG[2], T);
+    //real t = (x3 / z3 - x1z1) / (x2z2 - x1z1);
+    //Result[0] = tnsLinearItp(L[0], R[0], t);
+    //Result[1] = tnsLinearItp(L[1], R[1], t);
+    //Result[2] = tnsLinearItp(L[2], R[2], t);
+}
+
+tnsLineStrip *tnsCreateLineStrip(){
+    tnsLineStrip *ls = CreateNew(tnsLineStrip);
+    return ls;
+}
+tnsLineStripPoint *tnsAppendPoint(tnsLineStrip *ls, real X, real Y, real Z){
+    tnsLineStripPoint *lsp = CreateNew(tnsLineStripPoint);
+
+    lsp->P[0] = X;
+    lsp->P[1] = Y;
+    lsp->P[2] = Z;
+
+    lstAppendItem(&ls->Points, lsp);
+
+    ls->PointCount++;
+
+    return lsp;
+}
+tnsLineStripPoint *tnsPushPoint(tnsLineStrip *ls, real X, real Y, real Z){
+    tnsLineStripPoint *lsp = CreateNew(tnsLineStripPoint);
+
+    lsp->P[0] = X;
+    lsp->P[1] = Y;
+    lsp->P[2] = Z;
+
+    lstPushItem(&ls->Points, lsp);
+
+    ls->PointCount++;
+
+    return lsp;
+}
+
+void tnsRemovePoint(tnsLineStrip *ls, tnsLineStripPoint *lsp){
+    lstRemoveItem(&ls->Points, lsp);
+    FreeMem(lsp);
+}
+
+void tnsDestroyLineStrip(tnsLineStrip *ls){
+    tnsLineStripPoint *lsp;
+    while (lsp = lstPopItem(&ls->Points)){
+        FreeMem(lsp);
+    }
+    FreeMem(ls);
+}

+ 3955 - 0
source/lagui/la_tns_kernel.c

@@ -0,0 +1,3955 @@
+#include "la_5.h"
+//#include <gl/glew.h>
+
+/*
+NUL4.0 - Nick's Best - www.nicksbest.com
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@  TNS OpenGL 2D/3D Rendering System  @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@@                  __                 @@
+@@            ___---  |                @@
+@@      __----     @@  ||              @@
+@@  _---  _         @@@  ||            @@
+@@   |  @@@__         @@   ||          @@
+@@    |  @@ #@@@#_     @@@   ||        @@
+@@     |  @@     `#@@@@  @@    |_      @@
+@@      |  @@         `#@@@@@_--       @@
+@@       |  @@          _--'           @@
+@@        |  @@     _---               @@
+@@         |  @@_---                   @@
+@@          |_--          _ __ __ __ __@@
+@@                       |  Not Fancy  @@
+@@                       |  But Easy   @@
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+Author(s):WuYiming - xp8110@outlook.com
+
+Want to join the development?
+Append your name in the author list above.
+Send feedback to la_support@nicksbest.com
+*/
+
+#include <math.h>
+#include "freetype/ftadvanc.h"
+
+char TNS_VERTEX_SIMPLE_MATCAP[] = "#version 330\n"
+"uniform mat4 mProjection;\n"
+"uniform mat4 mModel;\n"
+"uniform mat4 mView;\n"
+"\n"
+"in vec4 vVertex;\n"
+"in vec3 vNormal;\n"
+"smooth out vec3 fNormal;\n"
+"\n"
+"void main(){\n"
+"    gl_Position = mProjection * mView  * mModel * vVertex;\n"
+"    vec3 N = ( mView * mModel * vec4(vNormal,0)).xyz;\n"
+"    fNormal = normalize(N);\n"
+"}";
+char TNS_FRAGMENT_SIMPLE_MATCAP[] = "#version 330\n"
+"\n"
+"smooth in vec3 fNormal;"
+"\n"
+"float Interpolate(float between1,float between2,float value1,float value2,float key){\n"
+"    float i = (key-between1)/(between2-between1);\n"
+"    return value1*(1-i)+value2*i;"
+"}\n"
+"void main(){\n"
+"    float value = dot(vec3(0,0,1),fNormal);\n"
+"    if(value<0.65) value=0.15;\n"
+"    else if(value>=0.65 && value<0.85) value=Interpolate(0.65,0.85,0.15,0.75,value);\n"
+"    else if(value>=0.85 && value<0.95) value=0.75;\n"
+"    else if(value>=0.95) value=0.9;\n"
+"    gl_FragColor = vec4(vec3(0.84, 0.41, 0.16)*value,1);\n"
+"}";
+
+char TNS_VERTEX_GRID[] = "#version 330\n"
+"\n"
+"uniform mat4 mProjection;\n"
+"uniform mat4 mModel;\n"
+"uniform mat4 mView;\n"
+"\n"
+"in vec4 vVertex;\n"
+"in vec4 vColor;\n"
+"in vec2 vUV;\n"
+"out vec4 fColor;\n"
+"out vec2 uv;\n"
+"\n"
+"void main(){\n"
+"    vec4 pos = mProjection * mView * mModel * vVertex;\n"
+"    gl_Position = pos;\n"
+"    fColor = vColor;\n"
+"    uv = vUV;\n"
+"}";
+
+char TNS_FRAGMENT_TRANSPARNT_GRID[] = "#version 330\n"
+"\n"
+"in vec4 fColor;\n"
+"in vec2 uv;\n"
+"\n"
+"void main(){\n"
+"    vec4 c = fColor;\n"
+"    c.a = sin(uv.x)*sin(uv.y)>0?c.a:0;\n"
+"    gl_FragColor = c;\n"
+"}";
+
+const char LA_IMM_VERTEX_SHADER[] = "#version 330\n\
+uniform mat4 mProjection;\
+uniform mat4 mModel;\
+uniform mat4 mView;\
+in vec4 vVertex;\
+in vec4 vColor;\
+/*in vec4 vNormal;*/\
+in vec2 vUV;\
+out vec4 fColor;\
+out vec2 fUV;\
+void main(){\
+    gl_Position = mProjection * mView * mModel * vVertex;\
+    fColor = vColor;\
+    fUV=vUV;\
+}";
+const char LA_IMM_FRAGMENT_SHADER[] = "#version 330\n\
+uniform sampler2D TexColor;\
+uniform sampler2DMS TexColorMS;\
+uniform int TextureMode;\n\
+uniform int MultiplyColor;\n\
+uniform int SampleAmount;\n\
+in vec4 fColor;\n\
+in vec2 fUV;\n\
+void main(){\n\
+    vec4 color=vec4(1,0,1,1);\n\
+    if(TextureMode==0){ color = fColor;}\n\
+    else if(TextureMode==1){color = vec4(fColor.rgb,fColor.a*texture2D(TexColor,fUV.st).r);}\n\
+    else if(TextureMode==2){\n\
+        color=texture2D(TexColor,fUV.st);\n\
+        if(MultiplyColor!=0){color*=fColor;}\n\
+    }else if(TextureMode==3){\n\
+        color=vec4(0,0,0,0);\n\
+        ivec2 texSize = textureSize(TexColorMS);\n\
+        for(int i=0;i<SampleAmount;i++) color+=texelFetch(TexColorMS, ivec2(fUV * texSize),i);\n\
+        color/=SampleAmount;\n\
+        if(MultiplyColor!=0){color*=fColor;}\n\
+    }\n\
+    gl_FragColor = color;\n\
+}";
+const char LA_RAY_VERTEX_SHADER[] = "#version 330\n\
+in vec3 vUV;\n\
+in vec4 vVertex;\n\
+out vec3 fViewDir;\n\
+void main(){\n\
+    gl_Position=vVertex;\n\
+    fViewDir = vUV;\n\
+}";
+const char LA_RAY_FRAGMENT_SHADER[] = "#version 330\n\
+uniform vec3 uViewDir;\n\
+uniform vec3 uViewPos;\n\
+uniform float uFOV;\n\
+in vec3 fViewDir;\n\
+void main(){\n\
+    float d=dot(uViewDir,normalize(fViewDir));\n\
+    float target=cos(uFOV/2.);\n\
+    vec4 color=vec4(1.,1.,1.,1.); float mul=0.;\n\
+    if(d<(target+0.005)&&d>target) mul=1.0;\n\
+    gl_FragColor = mul*color;\n\
+}";
+const char LA_SCENE_VERTEX_SHADER[] = "#version 330\n\
+uniform mat4 mProjection;\n\
+uniform mat4 mModel;\n\
+uniform mat4 mView;\n\
+uniform mat4 mShadow;\n\
+in vec4 vVertex;\n\
+in vec4 vColor;\n\
+in vec4 vNormal;\n\
+in vec2 vUV;\n\
+out vec4 fColor;\n\
+//out vec4 fNormal;\n\
+out vec2 fUV;\n\
+out vec4 fGPos;\n\
+void main(){\n\
+    gl_Position= mProjection * mView * mModel * vVertex;\n\
+    fUV=vUV;\n\
+    //fNormal=vNormal;\n\
+    fColor=vColor;\n\
+    fGPos= mShadow * mModel * vVertex;\
+}";
+const char LA_SCENE_FRAGMENT_SHADER[] = "#version 330\n\
+uniform sampler2D TexColor;\n\
+uniform sampler2DMS TexColorMS;\
+uniform int TextureMode;\n\
+uniform int SampleAmount;\n\
+uniform int MultiplyColor;\n\
+in vec4 fColor;\n\
+//in vec4 fNormal;\n\
+in vec2 fUV;\n\
+in vec4 fGPos;\n\
+vec4 GetTexture(vec2 uv){\n\
+    vec4 color=vec4(1,0,1,1);\n\
+    if(TextureMode==1 || TextureMode==2){ return texture2D(TexColor,uv); }\n\
+    else if(TextureMode==3){\n\
+        ivec2 texSize = textureSize(TexColorMS);\n\
+        for(int i=0;i<SampleAmount;i++) color+=texelFetch(TexColorMS, ivec2(fUV * texSize),i);\n\
+        color/=SampleAmount;\n\
+        if(MultiplyColor!=0){color*=fColor;}\n\
+        return color;\n\
+    }\n\
+    else return vec4(1,0,1,1);\n\
+}\n\
+float GetShadow(vec4 GPos){\n\
+    vec3 projCoords = GPos.xyz / GPos.w;\n\
+    projCoords = projCoords * 0.5 + 0.5;\n\
+    float closestDepth = GetTexture(projCoords.xy).r;\n\
+    float currentDepth = projCoords.z;\n\
+    float shadow = currentDepth > (closestDepth+0.001)  ? 0.5 : 1.0;\n\
+    return shadow;\n\
+}\n\
+void main(){\n\
+    gl_FragColor=GetShadow(fGPos)*fColor;\n\
+}";
+
+const char LA_CASCADE_SHADOW_VERTEX_SHADER[] = "#version 330\n\
+in vec4 vVertex;\n\
+uniform mat4 mModel;\n\
+uniform mat4 mShadow;\n\
+void main(){\n\
+    gl_Position=mShadow*mModel*vVertex;\n\
+}";
+const char LA_CASCADE_SHADOW_FRAGMENT_SHADER[] = "#version 330\nvoid main(){gl_FragDepth = gl_FragCoord.z;}";
+
+const char LA_SELECTION_VERTEX_SHADER[] = "#version 330\n\
+in vec4 vVertex;\n\
+in vec3 vColor;\n\
+uniform mat4 mProjection;\n\
+uniform mat4 mModel;\n\
+uniform mat4 mView;\n\
+flat out vec3 fIdColor;\n\
+void main(){\n\
+    gl_Position = mProjection * mView * mModel * vVertex;\n\
+    fIdColor = vColor;\n\
+}";
+const char LA_SELECTION_FRAGMENT_SHADER[] = "#version 330\n\
+flat in vec3 fIdColor;\n\
+void main(){\n\
+    gl_FragColor=vec4(fIdColor,1.);\n\
+}";
+
+int tKnlAttatchShader(tnsShader *tns);
+tnsShader *tKnlFindShader1i(int CustomIndex);
+void tKnlPushMatrix();
+void tKnlPopMatrix();
+
+laListHandle *tKnlGetTextureList();
+
+void tnsLoadIdentity44d(tnsMatrix44d m);
+void tnsMakeOrthoMatrix44d(tnsMatrix44d mProjection, real xMin, real xMax, real yMin, real yMax, real zMin, real zMax);
+void tnsMakePerspectiveMatrix44d(tnsMatrix44d mProjection, real fFov_rad, real fAspect, real zMin, real zMax);
+void tnsMakeTranslationMatrix44d(tnsMatrix44d mTrans, real x, real y, real z);
+void tnsMakeRotationMatrix44d(tnsMatrix44d m, real angle_rad, real x, real y, real z);
+void tnsMakeScaleMatrix44d(tnsMatrix44d m, real x, real y, real z);
+void tnsMultiply44d(tnsMatrix44d result, tnsMatrix44d l, tnsMatrix44d r);
+
+void tnsInitFirstLevel(tnsMatrixStack *tms);
+tnsMatrixStackItem *tKnlGetCurrentMatStackItem();
+tnsShader *tKnlGetActiveShader();
+
+void tnsAttach2DOffscreenBuffer(tnsOffscreen *target, GLuint attatchment, tnsTexture *use);
+void tnsDetach2DOffscreenBuffer(tnsOffscreen *target, GLuint which_attach_point);
+
+//=========================================================================================
+
+tnsMain *T;
+real DefaultZRange[2] = {0.1, 1000};
+
+//=======================================[SYS]
+extern LA MAIN;
+
+void InitGLRenderEnviornment(){
+    glEnable(GL_SCISSOR_TEST);
+};
+void tnsSwitchToCurrentWindowContext(void *wnd){
+    //HGLRC current = wglGetCurrentContext(), hglrc = wnd->SystemGLRC;
+    //HDC hdc = wnd->SystemDC;
+//
+    ////if (hglrc != current)
+    //int a = GetLastError();
+//
+    //int s = wglMakeCurrent(hdc, hglrc);
+    laWindow* win = wnd;
+    glXMakeContextCurrent(MAIN.dpy, win->win, win->win, MAIN.glc);
+};
+void tnsViewportWithScissor(int x, int y, int w, int h){
+    tnsShader *current_shader = 0;
+    glEnable(GL_SCISSOR_TEST);
+    glViewport(x, y, w, h);
+    glScissor(x, y, w, h);
+    if ((current_shader = tKnlGetActiveShader())){
+        tnsResetViewMatrix();
+        tnsShaderApplyView(current_shader, tnsGetViewMatrix());
+        tnsResetModelMatrix();
+        tnsShaderApplyModel(current_shader, tnsGetModelMatrix());
+    }
+}
+void tnsViewport(int x, int y, int w, int h){
+    glViewport(x, y, w, h);
+}
+//Must At Origion!
+
+//void UseWindowMatrix_WithScissor(laWndPlacement* wp){
+//	tnsViewportWithScissor(0, 0, VAL2_CLIENT_W_H(*wp));
+//	SetMatrix2Di(0, VAL2_CLIENT_W_H(*wp), 0);
+//};
+//void UseBlockMatrix_WithScissor(laBlockPlacement* bp){
+//	tnsViewportWithScissor(bp->UpperLeftX,
+//		bp->ClientHeight - bp->LowerRightY,
+//		bp->LowerRightX - bp->UpperLeftX,
+//		bp->LowerRightY - bp->UpperLeftY);
+//	SetMatrix2Di(0, bp->LowerRightX - bp->UpperLeftX,
+//		0, bp->UpperLeftY - bp->LowerRightY);
+//};
+
+void DrawWireRect2dp(real x, real y, real x2, real y2){
+    real Verts[8];
+    tnsMakeQuad2d(Verts, x, y, x2, y, x2, y2, x, y2);
+    tnsVertexArray2d(Verts, 4);
+    tnsPackAs(GL_LINE_LOOP);
+};
+void DrawWireRect4ds(real x, real y, real w, real h){
+    real Verts[8];
+    tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y + h, x, y + h);
+    tnsVertexArray2d(Verts, 4);
+    tnsPackAs(GL_LINE_LOOP);
+};
+void DrawWireRect4drs(real x, real y, real w, real h){
+    real Verts[8];
+    tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y - h, x, y - h);
+    tnsVertexArray2d(Verts, 4);
+    tnsPackAs(GL_LINE_LOOP);
+};
+void DrawSoildRect4drs(real x, real y, real w, real h){
+    real Verts[8];
+    tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y - h, x, y - h);
+    tnsVertexArray2d(Verts, 4);
+    tnsPackAs(GL_TRIANGLE_FAN);
+}
+void DrawWireCross4ds(real x, real y, real w, real h){
+    real Verts[8];
+    tnsMakeQuad2d(Verts, x, y, x + w, y + h, x + w, y, x, y + h);
+    tnsVertexArray2d(Verts, 4);
+    tnsPackAs(GL_LINES);
+};
+void DrawWireCross4drs(real x, real y, real w, real h){
+    real Verts[8];
+    tnsMakeQuad2d(Verts, x, y, x + w, y - h, x + w, y, x, y - h);
+    tnsVertexArray2d(Verts, 4);
+    tnsPackAs(GL_LINES);
+};
+void DrawGrid6f(real L, real R, real U, real B, real stepX, real stepY){
+    //do nothing;
+}
+void DrawSolidArrow1i3d(int direction, real xoff, real yoff, real size){
+    real size_2 = size / 2.0f;
+    real Verts[6];
+
+    switch (direction){
+    case TNS_ARROW_L:
+        tnsMakeTriangle(Verts,
+                        xoff + size_2, yoff,
+                        xoff, yoff - size_2,
+                        xoff + size_2, yoff - size);
+        break;
+    case TNS_ARROW_R:
+        tnsMakeTriangle(Verts,
+                        xoff, yoff,
+                        xoff + size_2, yoff - size_2,
+                        xoff, yoff - size);
+        break;
+    }
+
+    tnsPackAs(GL_TRIANGLES);
+}
+
+//=======================================[Shader]
+
+int tnsNextPowOf2(int i){
+    int result = 2;
+    while (result < i){
+        result *= 2;
+    }
+    return result;
+}
+
+void tnsShaderMakeIndex(tnsShader *tns){
+    int program;
+
+    if (!tns) return;
+
+    program = tns->glProgramID;
+
+    tns->iModel = glGetUniformLocation(program, "mModel");
+    tns->iProjection = glGetUniformLocation(program, "mProjection");
+    tns->iProjectionInverse = glGetUniformLocation(program, "mProjectionInverse");
+    tns->iView = glGetUniformLocation(program, "mView");
+    tns->iNormal = glGetUniformLocation(program, "mNormalScaler");
+    tns->iShadow = glGetUniformLocation(program, "mShadow");
+
+    tns->iVertex = glGetAttribLocation(program, "vVertex");
+    tns->iNormal = glGetAttribLocation(program, "vNormal");
+    tns->iColor = glGetAttribLocation(program, "vColor");
+    tns->iUV = glGetAttribLocation(program, "vUV");
+
+    tns->iTexColor = glGetUniformLocation(program, "TexColor");
+    tns->iTexColorMS = glGetUniformLocation(program, "TexColorMS");
+    tns->iMultiplyColor = glGetUniformLocation(program, "MultiplyColor");
+    tns->iTextureMode = glGetUniformLocation(program, "TextureMode");
+    tns->iSampleAmount = glGetUniformLocation(program, "SampleAmount");
+    if(tns->iTexColor>=0){glUniform1i(tns->iTexColor, 0);}
+    if(tns->iTexColorMS>=0){glUniform1i(tns->iTexColorMS, 1);}
+
+    tns->uViewDir = glGetUniformLocation(program, "uViewDir");
+    tns->uViewPos = glGetUniformLocation(program, "uViewPos");
+    tns->uFOV = glGetUniformLocation(program, "uFOV");
+}
+void tnsShaderApplyProjection(tnsShader *tns, tnsMatrix44d m){
+    tnsMatrix44f mf;
+    if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; }
+    tnsConvert44df(m, mf);
+    glUniformMatrix4fv(tns->iProjection, 1, 0, mf);
+}
+void tnsShaderApplyProjectionInverse(tnsShader *tns, tnsMatrix44d m){
+    tnsMatrix44f mf;
+    tnsMatrix44d i;
+    if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; }
+    tnsInverse44d(i, m);
+    tnsConvert44df(i, mf);
+    glUniformMatrix4fv(tns->iProjectionInverse, 1, 0, mf);
+}
+void tnsShaderApplyModel(tnsShader *tns, tnsMatrix44d m){
+    tnsMatrix44f mf;
+    if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; }
+    tnsConvert44df(m, mf);
+    glUniformMatrix4fv(tns->iModel, 1, 0, mf);
+}
+void tnsShaderApplyView(tnsShader *tns, tnsMatrix44d m){
+    tnsMatrix44f mf;
+    if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; }
+    tnsConvert44df(m, mf);
+    glUniformMatrix4fv(tns->iView, 1, 0, mf);
+}
+void tnsShaderApplyNormalScaler(tnsShader *tns, tnsMatrix44d m){
+    tnsMatrix44f mf;
+    if (tns->iNormal == -1) return;
+    if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; }
+    tnsConvert44df(m, mf);
+    glUniformMatrix4fv(tns->iNormal, 1, 0, mf);
+}
+void tnsShaderApplyShadowMatrix(tnsShader *tns, tnsMatrix44d m){
+    tnsMatrix44f mf;
+    if (tns->iShadow == -1) return;
+    if (T->BindedShader != tns){ glUseProgram(tns->glProgramID); T->BindedShader = tns; }
+    tnsConvert44df(m, mf);
+    glUniformMatrix4fv(tns->iShadow, 1, 0, mf);
+}
+
+//--------------------Export
+int tnsNewVertexShader(char *Content){
+    int status = 0;
+    char error[1024];
+    GLuint VertexShaderObject;
+    tnsShader *s = 0;
+
+    if (!Content) return -1;
+
+    VertexShaderObject = glCreateShader(GL_VERTEX_SHADER);
+
+    glShaderSource(VertexShaderObject, 1, &Content, 0);
+    glCompileShader(VertexShaderObject);
+    glGetShaderiv(VertexShaderObject, GL_COMPILE_STATUS, &status);
+    if (status == GL_FALSE){
+        glGetShaderInfoLog(VertexShaderObject, sizeof(error), 0, error);
+        printf("Vertex shader error:\n%s", error);
+        glDeleteShader(VertexShaderObject);
+        return -1;
+    }
+
+    return VertexShaderObject;
+}
+int tnsNewFragmentShader(char *Content){
+    int status = 0;
+    char error[1024];
+    GLuint FragmentShaderObject;
+    tnsShader *s = 0;
+
+    if (!Content) return -1;
+
+    FragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);
+
+    glShaderSource(FragmentShaderObject, 1, &Content, 0);
+    glCompileShader(FragmentShaderObject);
+    glGetShaderiv(FragmentShaderObject, GL_COMPILE_STATUS, &status);
+    if (status == GL_FALSE){
+        glGetShaderInfoLog(FragmentShaderObject, sizeof(error), 0, error);
+        printf("Fragment shader error:\n%s", error);
+        glDeleteShader(FragmentShaderObject);
+        return -1;
+    }
+
+    return FragmentShaderObject;
+}
+int tnsNewGeometryShader(char *Content){
+    int status = 0;
+    char error[1024];
+    GLuint GeometryShaderObject;
+    tnsShader *s = 0;
+
+    if (!Content) return -1;
+
+    GeometryShaderObject = glCreateShader(GL_GEOMETRY_SHADER);
+
+    glShaderSource(GeometryShaderObject, 1, &Content, 0);
+    glCompileShader(GeometryShaderObject);
+    glGetShaderiv(GeometryShaderObject, GL_COMPILE_STATUS, &status);
+    if (status == GL_FALSE){
+        glGetShaderInfoLog(GeometryShaderObject, sizeof(error), 0, error);
+        printf("Geometry shader error:\n%s", error);
+        glDeleteShader(GeometryShaderObject);
+        return -1;
+    }
+
+    return GeometryShaderObject;
+}
+
+tnsShader *tnsNewShaderProgram(int VertexShaderID, int FragmentShaderID, int GeometryShaderID){
+    int vso = VertexShaderID;
+    int fso = FragmentShaderID;
+    int gso = GeometryShaderID;
+    tnsShader *tns = 0;
+    int status = 0;
+    char error[1024];
+
+    if (!vso || !fso) return 0;
+
+    tns = CreateNew(tnsShader);
+    tns->vtShaderID = vso;
+    tns->fgShaderID = fso;
+    tns->glProgramID = glCreateProgram();
+    glAttachShader(tns->glProgramID, vso);
+    glAttachShader(tns->glProgramID, fso);
+    if (GeometryShaderID > -1){ glAttachShader(tns->glProgramID, gso); tns->gsShaderID=gso; }
+    glLinkProgram(tns->glProgramID);
+    glGetProgramiv(tns->glProgramID, GL_LINK_STATUS, &status);
+    if (status == GL_FALSE){
+        glGetProgramInfoLog(tns->glProgramID, sizeof(error), 0, error);
+        printf("Shader Linking error:\n%s", error);
+        glDetachShader(tns->glProgramID, vso);
+        glDetachShader(tns->glProgramID, fso);
+        glDeleteShader(vso);
+        glDeleteShader(fso);
+        glDeleteProgram(tns->glProgramID);
+        FreeMem(tns);
+        return 0;
+    }
+    glUseProgram(tns->glProgramID);
+
+    tnsShaderMakeIndex(tns);
+
+    return tns;
+}
+int tnsEnableShader(int index){
+    tnsMatrixStackItem *tmsi;
+    tnsShader *tns = tKnlFindShader1i(index);
+    if (!tns){
+        glUseProgram(0);
+        T->CurrentShader = 0;
+        T->BindedShader = 0;
+        return 0;
+    }
+    glUseProgram(tns->glProgramID);
+    T->CurrentShader = tns;
+    T->BindedShader = tns;
+
+    tmsi = tKnlGetCurrentMatStackItem();
+    tnsShaderApplyProjection(tns, tmsi->projection);
+    tnsShaderApplyView(tns, tmsi->view);
+    tnsShaderApplyModel(tns, tmsi->model);
+    return 1;
+}
+int tnsEnableShaderv(tnsShader *shader){
+    tnsMatrixStackItem *tmsi;
+    tnsShader *tns = shader;
+    if (!tns){
+        glUseProgram(0);
+        T->CurrentShader = 0;
+        T->BindedShader = 0;
+        return 0;
+    }
+    glUseProgram(tns->glProgramID);
+    T->CurrentShader = tns;
+    T->BindedShader = tns;
+
+    tmsi = tKnlGetCurrentMatStackItem();
+    tnsShaderApplyProjection(tns, tmsi->projection);
+    tnsShaderApplyProjectionInverse(tns, tmsi->projection);
+    tnsShaderApplyView(tns, tmsi->view);
+    tnsShaderApplyModel(tns, tmsi->model);
+
+    //if (tns->iVertex != -1) glEnableVertexAttribArray(tns->iVertex);
+    //if (tns->iColor != -1) glEnableVertexAttribArray(tns->iColor);
+    //if (tns->iNormal != -1) glEnableVertexAttribArray(tns->iNormal);
+    //if (tns->iUV != -1) glEnableVertexAttribArray(tns->iUV);
+
+    return 1;
+}
+int tnsUseShader(tnsShader *shader){
+    T->StateShader = shader;
+}
+void tnsDeleteShaderProgram(tnsShader* s){
+    tnsUseShader(0); tnsEnableShaderv(0);
+    if(s->vtShaderID>-1) glDeleteShader(s->vtShaderID);
+    if(s->fgShaderID>-1) glDeleteShader(s->fgShaderID);
+    if(s->gsShaderID>-1) glDeleteShader(s->gsShaderID);
+    glDeleteProgram(s->glProgramID);
+    free(s);
+}
+
+void tnsUseImmShader(){
+    T->StateShader = T->immShader;
+}
+void tnsUseTransparentGridShader(){
+    T->StateShader = T->TransparentGridShader;
+}
+void tnsUseExtraBufferShader(){
+    T->StateShader = T->ExtraBuffersShader;
+}
+void tnsUseRayShader(){
+    T->StateShader = T->RayShader;
+}
+void tnsUseShadowShader(){
+    T->StateShader = T->ShadowShader;
+}
+void tnsUseSceneShader(){
+    T->StateShader = T->SceneShader;
+}
+
+//=======================================[MAT]
+
+int tnsLineIntersectTest2d(tnsVector2d a1, tnsVector2d a2, tnsVector2d b1, tnsVector2d b2, double *aRatio){
+    double k1, k2;
+    double x;
+    double y;
+    double Ratio;
+    double xDiff = (a2[0] - a1[0]); // +DBL_EPSILON;
+    double xDiff2 = (b2[0] - b1[0]);
+
+    if (xDiff == 0){
+        if (xDiff2 == 0){
+            *aRatio = 0;
+            return 0;
+        }
+        double r2 = tnsGetRatiod(b1[0], b2[0], a1[0]);
+        y = tnsLinearItp(b1[1], b2[1], r2);
+        *aRatio = Ratio = tnsGetRatiod(a1[1], a2[1], y);
+    }else{
+        if (xDiff2 == 0){
+            Ratio = tnsGetRatiod(a1[0], a2[0], b1[0]);
+            //y = tnsLinearItp(a1[1], a2[1], r2);
+            *aRatio = Ratio;
+        }else{
+            k1 = (a2[1] - a1[1]) / xDiff;
+            k2 = (b2[1] - b1[1]) / xDiff2;
+
+            if ((k1 == k2)) return 0;
+
+            x = (a1[1] - b1[1] - k1 * a1[0] + k2 * b1[0]) / (k2 - k1);
+
+            Ratio = (x - a1[0]) / xDiff;
+
+            *aRatio = Ratio;
+        }
+    }
+
+    if (b1[0] == b2[0]){
+        y = tnsLinearItp(a1[1], a2[1], Ratio);
+        if (y > TNS_MAX2(b1[1], b2[1]) || y < TNS_MIN2(b1[1], b2[1])) return 0;
+    }else if (Ratio <= 0 || Ratio > 1 ||
+             (b1[0] > b2[0] && x > b1[0]) ||
+             (b1[0] < b2[0] && x < b1[0]) ||
+             (b2[0] > b1[0] && x > b2[0]) ||
+             (b2[0] < b1[0] && x < b2[0]))
+        return 0;
+
+    return 1;
+}
+double tnsGetLineZ(tnsVector3d L, tnsVector3d R, real Ratio){
+    //double z = 1 / tnsLinearItp(1 / L[2], 1 / R[2], Ratio);
+    double z = tnsLinearItp(L[2], R[2], Ratio);
+    return z;
+}
+double tnsGetLineZPoint(tnsVector3d L, tnsVector3d R, tnsVector3d FromL){
+    double r = (FromL[0] - L[0]) / (R[0] - L[0]);
+    return tnsLinearItp(L[2], R[2], r);
+    //return 1 / tnsLinearItp(1 / L[2], 1 / R[2], r);
+}
+double tnsGetRatio3d(tnsVector3d L, tnsVector3d R, tnsVector3d FromL){
+    double r = (FromL[0] - L[0]) / (R[0] - L[0]);
+    return r;
+}
+
+double tnsGetRatiod(real L, real R, real FromL){
+    double r = (FromL - L) / (R - L);
+    return r;
+}
+
+void tnsInterpolateTripple2d(tnsVector2d v1, tnsVector2d v2, tnsVector2d v3, real ratio, tnsVector2d result){
+    tnsVector2d i1,i2;
+    tnsInterpolate2dv(v1,v2,ratio,i1);
+    tnsInterpolate2dv(v2,v3,ratio,i2);
+    tnsInterpolate2dv(i1,i2,ratio,result);
+}
+
+void tnsVectorMinus2d(tnsVector2d result, tnsVector2d l, tnsVector2d r){
+    result[0] = l[0] - r[0];
+    result[1] = l[1] - r[1];
+}
+void tnsVectorMinus3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){
+    result[0] = l[0] - r[0];
+    result[1] = l[1] - r[1];
+    result[2] = l[2] - r[2];
+}
+void tnsVectorSubtract3d(tnsVector3d l, tnsVector3d r){
+    l[0] = l[0] - r[0];
+    l[1] = l[1] - r[1];
+    l[2] = l[2] - r[2];
+}
+void tnsVectorPlus3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){
+    result[0] = l[0] + r[0];
+    result[1] = l[1] + r[1];
+    result[2] = l[2] + r[2];
+}
+void tnsVectorAccum3d(tnsVector3d l, tnsVector3d r){
+    l[0] = l[0] + r[0];
+    l[1] = l[1] + r[1];
+    l[2] = l[2] + r[2];
+}
+void tnsVectorAccum2d(tnsVector2d l, tnsVector2d r){
+    l[0] = l[0] + r[0];
+    l[1] = l[1] + r[1];
+}
+void tnsVectorNegate3d(tnsVector3d result, tnsVector3d l){
+    result[0] = -l[0];
+    result[1] = -l[1];
+    result[2] = -l[2];
+}
+void tnsVectorNegateSelf3d(tnsVector3d l){
+    l[0] = -l[0];
+    l[1] = -l[1];
+    l[2] = -l[2];
+}
+void tnsVectorCopy2d(tnsVector2d from, tnsVector2d to){
+    to[0] = from[0];
+    to[1] = from[1];
+}
+void tnsVectorCopy3d(tnsVector3d from, tnsVector3d to){
+    to[0] = from[0];
+    to[1] = from[1];
+    to[2] = from[2];
+}
+void tnsVectorCopy4d(tnsVector4d from, tnsVector4d to){
+    to[0] = from[0];
+    to[1] = from[1];
+    to[2] = from[2];
+    to[3] = from[3];
+}
+void tnsVectorMultiSelf4d(tnsVector4d from, real num){
+    from[0] *= num;
+    from[1] *= num;
+    from[2] *= num;
+    from[3] *= num;
+}
+void tnsVectorMultiSelf3d(tnsVector3d from, real num){
+    from[0] *= num;
+    from[1] *= num;
+    from[2] *= num;
+}
+void tnsVectorMultiSelf2d(tnsVector2d from, real num){
+    from[0] *= num;
+    from[1] *= num;
+}
+void tnsVectorMulti4d(tnsVector4d to, tnsVector4d from, real num){
+    to[0]=from[0]*num;
+    to[1]=from[1]*num;
+    to[2]=from[2]*num;
+    to[3]=from[3]*num;
+}
+void tnsVectorMulti3d(tnsVector3d to, tnsVector3d from, real num){
+    to[0]=from[0]*num;
+    to[1]=from[1]*num;
+    to[2]=from[2]*num;
+}
+void tnsVectorMulti2d(tnsVector2d to, tnsVector2d from, real num){
+    to[0]=from[0]*num;
+    to[1]=from[1]*num;
+}
+
+real tnsDirectionToRad(tnsVector2d Dir){
+    real arcc = acos(Dir[0]);
+    real arcs = asin(Dir[1]);
+
+    if (Dir[0] >= 0){
+        if (Dir[1] >= 0) return arcc;
+        else
+            return TNS_PI * 2 - arcc;
+    }else{
+        if (Dir[1] >= 0) return arcs + TNS_PI / 2;
+        else
+            return TNS_PI + arcs;
+    }
+}
+void tnsConvert44df(tnsMatrix44d from, tnsMatrix44f to){
+    to[0] = from[0];
+    to[1] = from[1];
+    to[2] = from[2];
+    to[3] = from[3];
+    to[4] = from[4];
+    to[5] = from[5];
+    to[6] = from[6];
+    to[7] = from[7];
+    to[8] = from[8];
+    to[9] = from[9];
+    to[10] = from[10];
+    to[11] = from[11];
+    to[12] = from[12];
+    to[13] = from[13];
+    to[14] = from[14];
+    to[15] = from[15];
+}
+
+void tnsLoadIdentity44d(tnsMatrix44d m){
+    memset(m, 0, sizeof(tnsMatrix44d));
+    m[0] = 1.0f;
+    m[5] = 1.0f;
+    m[10] = 1.0f;
+    m[15] = 1.0f;
+};
+
+real tnsDistIdv2(real x1, real y1, real x2, real y2){
+    real x = x2 - x1, y = y2 - y1;
+    return sqrt((x * x + y * y));
+}
+real tnsDist3dv(tnsVector3d l, tnsVector3d r){
+    real x = r[0] - l[0];
+    real y = r[1] - l[1];
+    real z = r[2] - l[2];
+    return sqrt(x * x + y * y + z * z);
+}
+real tnsDist2dv(tnsVector2d l, tnsVector2d r){
+    real x = r[0] - l[0];
+    real y = r[1] - l[1];
+    return sqrt(x * x + y * y);
+}
+
+real tnsLength3d(tnsVector3d l){
+    return (sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]));
+}
+real tnsLength2d(tnsVector3d l){
+    return (sqrt(l[0] * l[0] + l[1] * l[1]));
+}
+void tnsNormalize3d(tnsVector3d result, tnsVector3d l){
+    real r = sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]);
+    result[0] = l[0] / r;
+    result[1] = l[1] / r;
+    result[2] = l[2] / r;
+}
+void tnsNormalize2d(tnsVector2d result, tnsVector2d l){
+    real r = sqrt(l[0] * l[0] + l[1] * l[1]);
+    result[0] = l[0] / r;
+    result[1] = l[1] / r;
+}
+void tnsNormalizeSelf2d(tnsVector3d result){
+    real r = sqrt(result[0] * result[0] + result[1] * result[1]);
+    result[0] /= r;
+    result[1] /= r;
+}
+void tnsNormalizeSelf3d(tnsVector3d result){
+    real r = sqrt(result[0] * result[0] + result[1] * result[1] + result[2] * result[2]);
+    result[0] /= r;
+    result[1] /= r;
+    result[2] /= r;
+}
+real tnsDot3d(tnsVector3d l, tnsVector3d r, int normalize){
+    tnsVector3d ln, rn;
+    if (normalize){
+        tnsNormalize3d(ln, l);
+        tnsNormalize3d(rn, r);
+        return (ln[0] * rn[0] + ln[1] * rn[1] + ln[2] * rn[2]);
+    }
+    return (l[0] * r[0] + l[1] * r[1] + l[2] * r[2]);
+}
+real tnsDot2d(tnsVector2d l, tnsVector2d r, int normalize){
+    tnsVector3d ln, rn;
+    if (normalize){
+        tnsNormalize2d(ln, l);
+        tnsNormalize2d(rn, r);
+        return (ln[0] * rn[0] + ln[1] * rn[1]);
+    }
+    return (l[0] * r[0] + l[1] * r[1]);
+}
+real tnsVectorCross3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){
+    result[0] = l[1] * r[2] - l[2] * r[1];
+    result[1] = l[2] * r[0] - l[0] * r[2];
+    result[2] = l[0] * r[1] - l[1] * r[0];
+    return tnsLength3d(result);
+}
+void tnsVectorCrossOnly3d(tnsVector3d result, tnsVector3d l, tnsVector3d r){
+    result[0] = l[1] * r[2] - l[2] * r[1];
+    result[1] = l[2] * r[0] - l[0] * r[2];
+    result[2] = l[0] * r[1] - l[1] * r[0];
+}
+real tnsAngleRad3d(tnsVector3d from, tnsVector3d to, tnsVector3d PositiveReference){
+    if (PositiveReference){
+        tnsVector3d res;
+        tnsVectorCross3d(res, from, to);
+        if (tnsDot3d(res, PositiveReference, 1) > 0) return acosf(tnsDot3d(from, to, 1));
+        else
+            return -acosf(tnsDot3d(from, to, 1));
+    }
+    return acosf(tnsDot3d(from, to, 1));
+}
+void tnsApplyRotation33d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){
+    result[0] = mat[0] * v[0] + mat[1] * v[1] + mat[2] * v[2];
+    result[1] = mat[3] * v[0] + mat[4] * v[1] + mat[5] * v[2];
+    result[2] = mat[6] * v[0] + mat[7] * v[1] + mat[8] * v[2];
+}
+void tnsApplyRotation43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){
+    result[0] = mat[0] * v[0] + mat[1] * v[1] + mat[2] * v[2];
+    result[1] = mat[4] * v[0] + mat[5] * v[1] + mat[6] * v[2];
+    result[2] = mat[8] * v[0] + mat[9] * v[1] + mat[10] * v[2];
+}
+void tnsApplyTransform43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){
+    real w;
+    result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * 1;
+    result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * 1;
+    result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * 1;
+    w = mat[3] * v[0] + mat[7] * v[1] + mat[11] * v[2] + mat[15] * 1;
+    //result[0] /= w;
+    //result[1] /= w;
+    //result[2] /= w;
+}
+void tnsApplyNormalTransform43d(tnsVector3d result, tnsMatrix44d mat, tnsVector3d v){
+    real w;
+    result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * 1;
+    result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * 1;
+    result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * 1;
+}
+void tnsApplyTransform44d(tnsVector4d result, tnsMatrix44d mat, tnsVector4d v){
+    result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * 1;
+    result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * 1;
+    result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * 1;
+    result[3] = mat[3] * v[0] + mat[7] * v[1] + mat[11] * v[2] + mat[15] * 1;
+}
+void tnsApplyTransform44dTrue(tnsVector4d result, tnsMatrix44d mat, tnsVector4d v){
+    result[0] = mat[0] * v[0] + mat[4] * v[1] + mat[8] * v[2] + mat[12] * v[3];
+    result[1] = mat[1] * v[0] + mat[5] * v[1] + mat[9] * v[2] + mat[13] * v[3];
+    result[2] = mat[2] * v[0] + mat[6] * v[1] + mat[10] * v[2] + mat[14] * v[3];
+    result[3] = mat[3] * v[0] + mat[7] * v[1] + mat[11] * v[2] + mat[15] * v[3];
+}
+
+void tnsRemoveTranslation44d(tnsMatrix44d result, tnsMatrix44d mat){
+    tnsLoadIdentity44d(result);
+    result[0] = mat[0];
+    result[1] = mat[1];
+    result[2] = mat[2];
+    result[4] = mat[4];
+    result[5] = mat[5];
+    result[6] = mat[6];
+    result[8] = mat[8];
+    result[9] = mat[9];
+    result[10] = mat[10];
+}
+void tnsClearTranslation44d(tnsMatrix44d mat){
+    mat[3] = 0;
+    mat[7] = 0;
+    mat[11] = 0;
+}
+
+void tnsExtractXYZEuler44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result){
+    real xRot, yRot, zRot;
+
+    if (mat[2] < 1){
+        if (mat[2] > -1){
+            yRot = asin(mat[2]);
+            xRot = atan2(-mat[6], mat[10]);
+            zRot = atan2(-mat[1], mat[0]);
+        }else{
+            yRot = -TNS_PI / 2;
+            xRot = -atan2(-mat[4], mat[5]);
+            zRot = 0;
+        }
+    }else{
+        yRot = TNS_PI / 2;
+        xRot = atan2(-mat[4], mat[5]);
+        zRot = 0;
+    }
+
+    (*x_result) = -xRot;
+    (*y_result) = -yRot;
+    (*z_result) = -zRot;
+}
+void tnsExtractLocation44d(tnsMatrix44d mat, real *x_result, real *y_result, real *z_result){
+    *x_result = mat[12];
+    *y_result = mat[13];
+    *z_result = mat[14];
+}
+void tnsExtractUniformScale44d(tnsMatrix44d mat, real *result){
+    tnsVector3d v = {mat[0], mat[1], mat[2]};
+    *result = tnsLength3d(v);
+}
+
+#define L(row, col) l[(col << 2) + row]
+#define R(row, col) r[(col << 2) + row]
+#define P(row, col) result[(col << 2) + row]
+
+void tnsPrintMatrix44d(tnsMatrix44d l){
+    int i, j;
+    for (i = 0; i < 4; i++){
+        for (j = 0; j < 4; j++){
+            printf("%.5f ", L(i, j));
+        }
+        printf("\n");
+    }
+}
+
+void tnsCopyMatrix44d(tnsMatrix44d from, tnsMatrix44d to){
+    memcpy(to, from, sizeof(tnsMatrix44d));
+}
+void tnsMultiply44d(tnsMatrix44d result, tnsMatrix44d l, tnsMatrix44d r){
+    int i;
+    for (i = 0; i < 4; i++){
+        real ai0 = L(i, 0), ai1 = L(i, 1), ai2 = L(i, 2), ai3 = L(i, 3);
+        P(i, 0) = ai0 * R(0, 0) + ai1 * R(1, 0) + ai2 * R(2, 0) + ai3 * R(3, 0);
+        P(i, 1) = ai0 * R(0, 1) + ai1 * R(1, 1) + ai2 * R(2, 1) + ai3 * R(3, 1);
+        P(i, 2) = ai0 * R(0, 2) + ai1 * R(1, 2) + ai2 * R(2, 2) + ai3 * R(3, 2);
+        P(i, 3) = ai0 * R(0, 3) + ai1 * R(1, 3) + ai2 * R(2, 3) + ai3 * R(3, 3);
+    }
+};
+void tnsInverse44d(tnsMatrix44d inverse, tnsMatrix44d mat){
+    int i, j, k;
+    double temp;
+    tnsMatrix44d tempmat;
+    real max;
+    int maxj;
+
+    tnsLoadIdentity44d(inverse);
+
+    tnsCopyMatrix44d(mat, tempmat);
+
+    for (i = 0; i < 4; i++){
+        /* Look for row with max pivot */
+        max = fabsf(tempmat[i * 5]);
+        maxj = i;
+        for (j = i + 1; j < 4; j++){
+            if (fabsf(tempmat[j * 4 + i]) > max){
+                max = fabsf(tempmat[j * 4 + i]);
+                maxj = j;
+            }
+        }
+
+        /* Swap rows if necessary */
+        if (maxj != i){
+            for (k = 0; k < 4; k++){
+                real t;
+                t = tempmat[i * 4 + k];
+                tempmat[i * 4 + k] = tempmat[maxj * 4 + k];
+                tempmat[maxj * 4 + k] = t;
+
+                t = inverse[i * 4 + k];
+                inverse[i * 4 + k] = inverse[maxj * 4 + k];
+                inverse[maxj * 4 + k] = t;
+            }
+        }
+
+        //if (UNLIKELY(tempmat[i][i] == 0.0f)) {
+        //	return false;  /* No non-zero pivot */
+        //}
+
+        temp = (double)tempmat[i * 5];
+        for (k = 0; k < 4; k++){
+            tempmat[i * 4 + k] = (real)((double)tempmat[i * 4 + k] / temp);
+            inverse[i * 4 + k] = (real)((double)inverse[i * 4 + k] / temp);
+        }
+        for (j = 0; j < 4; j++){
+            if (j != i){
+                temp = tempmat[j * 4 + i];
+                for (k = 0; k < 4; k++){
+                    tempmat[j * 4 + k] -= (real)((double)tempmat[i * 4 + k] * temp);
+                    inverse[j * 4 + k] -= (real)((double)inverse[i * 4 + k] * temp);
+                }
+            }
+        }
+    }
+}
+void tnsMakeTranslationMatrix44d(tnsMatrix44d mTrans, real x, real y, real z){
+    tnsLoadIdentity44d(mTrans);
+    mTrans[12] = x;
+    mTrans[13] = y;
+    mTrans[14] = z;
+}
+void tnsMakePerspectiveMatrix44d(tnsMatrix44d mProjection, real fFov_rad, real fAspect, real zMin, real zMax){
+    real yMax = zMin * tanf(fFov_rad * 0.5f);
+    real yMin = -yMax;
+    real xMin = yMin * fAspect;
+    real xMax = -xMin;
+
+    tnsLoadIdentity44d(mProjection);
+
+    mProjection[0] = (2.0f * zMin) / (xMax - xMin);
+    mProjection[5] = (2.0f * zMin) / (yMax - yMin);
+    mProjection[8] = (xMax + xMin) / (xMax - xMin);
+    mProjection[9] = (yMax + yMin) / (yMax - yMin);
+    mProjection[10] = -((zMax + zMin) / (zMax - zMin));
+    mProjection[11] = -1.0f;
+    mProjection[14] = -((2.0f * (zMax * zMin)) / (zMax - zMin));
+    mProjection[15] = 0.0f;
+}
+void tnsMakeZTrackingMatrix44d(tnsMatrix44d mat, tnsVector3d this, tnsVector3d that, tnsVector3d up){
+    tnsVector4d fwd, l, t, rt;
+    fwd[3] = l[3] = t[3] = rt[3] = 1;
+    t[0] = up[0];
+    t[1] = up[1];
+    t[2] = up[2];
+    fwd[0] = that[0] - this[0];
+    fwd[1] = that[1] - this[1];
+    fwd[2] = that[2] - this[2];
+    tnsNormalizeSelf3d(fwd);
+    tnsVectorCross3d(l, fwd, t);
+    tnsNormalizeSelf3d(l);
+    tnsVectorCross3d(rt, l, fwd);
+    tnsNormalizeSelf3d(rt);
+
+    tnsLoadIdentity44d(mat);
+
+    mat[0] = l[0];
+    mat[1] = l[1];
+    mat[2] = l[2];
+
+    mat[4] = rt[0];
+    mat[5] = rt[1];
+    mat[6] = rt[2];
+
+    mat[8] = -fwd[0];
+    mat[9] = -fwd[1];
+    mat[10] = -fwd[2];
+}
+void tnsMakeZTrackingMatrixDelta44d(tnsMatrix44d mat, tnsVector3d delta, tnsVector3d up){
+    tnsVector4d fwd, l, t, rt;
+    fwd[3] = l[3] = t[3] = rt[3] = 1;
+    t[0] = up[0];
+    t[1] = up[1];
+    t[2] = up[2];
+    fwd[0] = delta[0];
+    fwd[1] = delta[1];
+    fwd[2] = delta[2];
+
+    tnsLoadIdentity44d(mat);
+
+    tnsVectorCross3d(l, t, fwd);
+    tnsVectorCross3d(rt, fwd, l);
+
+    tnsNormalizeSelf3d(l);
+    tnsNormalizeSelf3d(rt);
+    tnsNormalizeSelf3d(fwd);
+
+    mat[0] = l[0];
+    mat[1] = l[1];
+    mat[2] = l[2];
+
+    mat[4] = rt[0];
+    mat[5] = rt[1];
+    mat[6] = rt[2];
+
+    mat[8] = fwd[0];
+    mat[9] = fwd[1];
+    mat[10] = fwd[2];
+}
+void tnsMakeOrthoMatrix44d(tnsMatrix44d mProjection, real xMin, real xMax, real yMin, real yMax, real zMin, real zMax){
+    tnsLoadIdentity44d(mProjection);
+
+    mProjection[0] = 2.0f / (xMax - xMin);
+    mProjection[5] = 2.0f / (yMax - yMin);
+    mProjection[10] = -2.0f / (zMax - zMin);
+    mProjection[12] = -((xMax + xMin) / (xMax - xMin));
+    mProjection[13] = -((yMax + yMin) / (yMax - yMin));
+    mProjection[14] = -((zMax + zMin) / (zMax - zMin));
+    mProjection[15] = 1.0f;
+}
+void tnsMakeRotationMatrix44d(tnsMatrix44d m, real angle_rad, real x_, real y_, real z_){
+    float x = x_;
+    float y = y_;
+    float z = z_;
+
+    float c = cos(angle_rad);
+    float s = sin(angle_rad);
+    tnsMatrix44d d={
+       x*x*(1.0f-c)+c,   x*y*(1.0f-c)-z*s, x*z*(1.0f-c)+y*s, 0.0f,
+       y*x*(1.0f-c)+z*s, y*y*(1.0f-c)+c,   y*z*(1.0f-c)-x*s, 0.0f,
+       z*x*(1.0f-c)-y*s, z*y*(1.0f-c)+x*s, z*z*(1.0f-c)+c,   0.0f,
+       0.0f,             0.0f,             0.0f,             1.0f };
+    memcpy(m,d,sizeof(tnsMatrix44d));
+}
+void tnsMakeRotationXMatrix44d(tnsMatrix44d m, real angle_rad){
+    tnsLoadIdentity44d(m);
+    m[5] = cos(angle_rad);
+    m[6] = sin(angle_rad);
+    m[9] = -sin(angle_rad);
+    m[10] = cos(angle_rad);
+}
+void tnsMakeRotationYMatrix44d(tnsMatrix44d m, real angle_rad){
+    tnsLoadIdentity44d(m);
+    m[0] = cos(angle_rad);
+    m[2] = -sin(angle_rad);
+    m[8] = sin(angle_rad);
+    m[10] = cos(angle_rad);
+}
+void tnsMakeRotationZMatrix44d(tnsMatrix44d m, real angle_rad){
+    tnsLoadIdentity44d(m);
+    m[0] = cos(angle_rad);
+    m[1] = sin(angle_rad);
+    m[4] = -sin(angle_rad);
+    m[5] = cos(angle_rad);
+}
+void tnsMakeScaleMatrix44d(tnsMatrix44d m, real x, real y, real z){
+    tnsLoadIdentity44d(m);
+    m[0] = x;
+    m[5] = y;
+    m[10] = z;
+}
+void tnsMakeViewportMatrix44d(tnsMatrix44d m, real w, real h, real Far, real Near){
+    tnsLoadIdentity44d(m);
+    m[0] = w / 2;
+    m[5] = h / 2;
+    m[10] = (Far - Near) / 2;
+    m[12] = w / 2;
+    m[13] = h / 2;
+    m[14] = (Far + Near) / 2;
+    m[15] = 1;
+    //m[0] = 2/w;
+    //m[5] = 2/h;
+    //m[10] = 1;
+    //m[12] = 2/w;
+    //m[13] = 2/h;
+    //m[14] = 1;
+    //m[15] = 1;
+}
+
+void tnsInitFirstLevel(tnsMatrixStack *tms){
+    tnsLoadIdentity44d(tms->level[0].model);
+    tnsLoadIdentity44d(tms->level[0].projection);
+    tnsLoadIdentity44d(tms->level[0].view);
+}
+
+//-------------------Export
+
+void tnsOrtho(real xMin, real xMax, real yMin, real yMax, real zMin, real zMax){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetProjectionMatrix();
+
+    tnsMakeOrthoMatrix44d(mat, xMin, xMax, yMin, yMax, zMin, zMax);
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyProjection(current_shader, mat);
+    }
+}
+void tnsPerspective(real fFov_rad, real fAspect, real zMin, real zMax){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetProjectionMatrix();
+
+    tnsMakePerspectiveMatrix44d(mat, fFov_rad, fAspect, zMin, zMax);
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyProjection(current_shader, mat);
+    }
+}
+
+void tnsTranslate3d(real x, real y, real z){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetModelMatrix();
+    tnsMatrix44d transmat, result;
+
+    tnsMakeTranslationMatrix44d(transmat, x, y, z);
+    tnsMultiply44d(result, mat, transmat);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyModel(current_shader, result);
+    }
+}
+void tnsPreTranslate3d(real x, real y, real z){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetModelMatrix();
+    tnsMatrix44d transmat, result;
+
+    //glTranslatef(x, y, z);
+
+    tnsMakeTranslationMatrix44d(transmat, x, y, z);
+    tnsMultiply44d(result, mat, transmat);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+}
+void tnsRotate4d(real degrees, real x, real y, real z){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetModelMatrix();
+    tnsMatrix44d rotmat, result;
+
+    tnsMakeRotationMatrix44d(rotmat, rad(degrees), x, y, z);
+    tnsMultiply44d(result, mat, rotmat);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyModel(current_shader, result);
+    }
+}
+void tnsPreRotate4d(real degrees, real x, real y, real z){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetModelMatrix();
+    tnsMatrix44d rotmat, result;
+
+    tnsMakeRotationMatrix44d(rotmat, rad(degrees), x, y, z);
+    tnsMultiply44d(result, mat, rotmat);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+}
+void tnsScale3d(real x, real y, real z){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetModelMatrix();
+    tnsMatrix44d scalemat, normal_scaler, result;
+
+    glScalef(x, y, z);
+
+    tnsMakeScaleMatrix44d(scalemat, x, y, z);
+
+    tnsMultiply44d(result, mat, scalemat);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyModel(current_shader, result);
+    }
+}
+void tnsPreScale3d(real x, real y, real z){
+    tnsShader *current_shader = 0;
+    real *mat = tnsGetModelMatrix();
+    tnsMatrix44d scalemat, normal_scaler, result;
+
+    glScalef(x, y, z);
+
+    tnsMakeScaleMatrix44d(scalemat, x, y, z);
+
+    tnsMultiply44d(result, mat, scalemat);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+}
+
+void tKnlPopMatrix();
+void tKnlPushMatrix();
+void tnsPushMatrix(){
+    tKnlPushMatrix();
+};
+void tnsPopMatrix(){
+    tKnlPopMatrix();
+}
+
+//========================================[KNL]
+
+void tnsInitRenderKernel(int matrixStackLevel){
+    tnsCommand *c;
+    T = memAcquireHyper(sizeof(tnsMain));
+    GLuint m_nQuadVAO;
+
+    T->GLVersionStr = glGetString(GL_VERSION);
+    T->GLVendorStr = glGetString(GL_VENDOR);
+    T->GLRendererStr = glGetString(GL_RENDERER);
+    T->GLSLVersionStr = glGetString(GL_SHADING_LANGUAGE_VERSION);
+
+    T->stack.max_level = matrixStackLevel;
+    T->stack.level = CreateNewBuffer(tnsMatrixStackItem, matrixStackLevel);
+    T->NextShaderIndex = 1;
+    T->BindedShader = -1;
+    tnsInitFirstLevel(&T->stack);
+
+    /* Needed for gl3.3+ */
+    glGenVertexArrays(1,&T->GlobalVAO);
+    glBindVertexArray(T->GlobalVAO);
+
+    arrEnsureLength(&T->Vert, T->NextVert, &T->MaxVert, sizeof(GLfloat));
+    glGenBuffers(1, &T->VertBufObject);
+    glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+    glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+
+    arrEnsureLength(&T->Color, T->NextColor, &T->MaxColor, sizeof(GLfloat));
+    glGenBuffers(1, &T->ColorBufObject);
+    glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject);
+    glBufferData(GL_ARRAY_BUFFER, T->MaxColor * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+
+    arrEnsureLength(&T->Normal, T->NextNormal, &T->MaxNormal, sizeof(GLfloat));
+    glGenBuffers(1, &T->NormalBufObject);
+    glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject);
+    glBufferData(GL_ARRAY_BUFFER, T->MaxNormal * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+
+    arrEnsureLength(&T->TexCoord, T->NextTexCoord, &T->MaxTexCoord, sizeof(GLfloat));
+    glGenBuffers(1, &T->TexCoordBufObject);
+    glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
+    glBufferData(GL_ARRAY_BUFFER, T->MaxTexCoord * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+
+    arrEnsureLength(&T->Index, T->NextIndex, &T->MaxIndex, sizeof(GLuint));
+    glGenBuffers(1, &T->IndexBufObject);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, T->IndexBufObject);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, T->MaxIndex * sizeof(GLuint), 0, GL_DYNAMIC_DRAW);
+
+    arrEnsureLength(&T->DrawingCommand, T->NextCommand, &T->MaxCommand, sizeof(tnsCommand));
+}
+void tnsInitBuiltinShaders(){
+    T->immShader = tnsNewShaderProgram(
+        tnsNewVertexShader(LA_IMM_VERTEX_SHADER),tnsNewFragmentShader(LA_IMM_FRAGMENT_SHADER),-1);
+
+    T->TEST_MatcapShader = tnsNewShaderProgram(
+        tnsNewVertexShader(TNS_VERTEX_SIMPLE_MATCAP),
+        tnsNewFragmentShader(TNS_FRAGMENT_SIMPLE_MATCAP), -1);
+
+    T->TransparentGridShader = tnsNewShaderProgram(
+        tnsNewVertexShader(TNS_VERTEX_GRID),
+        tnsNewFragmentShader(TNS_FRAGMENT_TRANSPARNT_GRID), -1);
+
+    T->RayShader = tnsNewShaderProgram(
+        tnsNewVertexShader(LA_RAY_VERTEX_SHADER),
+        tnsNewFragmentShader(LA_RAY_FRAGMENT_SHADER), -1);
+
+    T->ShadowShader = tnsNewShaderProgram(
+        tnsNewVertexShader(LA_CASCADE_SHADOW_VERTEX_SHADER),
+        tnsNewFragmentShader(LA_CASCADE_SHADOW_FRAGMENT_SHADER), -1);
+
+    T->SceneShader = tnsNewShaderProgram(
+        tnsNewVertexShader(LA_SCENE_VERTEX_SHADER),
+        tnsNewFragmentShader(LA_SCENE_FRAGMENT_SHADER), -1);
+
+    T->SelectionShader = tnsNewShaderProgram(
+        tnsNewVertexShader(LA_SELECTION_VERTEX_SHADER),
+        tnsNewFragmentShader(LA_SELECTION_FRAGMENT_SHADER), -1);
+
+    tnsUseShader(T->immShader);
+    tnsEnableShaderv(T->immShader);
+}
+void tnsInitWindowDefaultRenderConfig(){
+    tnsInitBuiltinShaders();
+};
+void tnsDeleteBuiltinShaders(){
+    tnsDeleteShaderProgram(T->immShader); T->immShader=0;
+    tnsDeleteShaderProgram(T->TEST_MatcapShader); T->TEST_MatcapShader=0;
+    tnsDeleteShaderProgram(T->TransparentGridShader); T->TransparentGridShader=0;
+}
+void tnsQuit(){
+    tnsDeleteBuiltinShaders();
+
+    tnsTexture* t; while(t=T->Textures.pFirst){ tnsDeleteTexture(t); }
+    
+    arrFree(&T->Vert, &T->MaxVert);
+    arrFree(&T->Color, &T->MaxColor);
+    arrFree(&T->Normal, &T->MaxNormal);
+    arrFree(&T->TexCoord, &T->MaxTexCoord);
+    arrFree(&T->Index, &T->MaxIndex);
+
+    glDeleteBuffers(1, &T->VertBufObject);
+    glDeleteBuffers(1, &T->ColorBufObject);
+    glDeleteBuffers(1, &T->NormalBufObject);
+    glDeleteBuffers(1, &T->TexCoordBufObject);
+    glDeleteBuffers(1, &T->IndexBufObject);
+
+    glBindVertexArray(0);
+    glDeleteVertexArrays(1,&T->GlobalVAO);
+
+    FreeMem(T->stack.level);
+    memFree(T);
+}
+
+tnsMatrixStackItem *tKnlGetCurrentMatStackItem(){
+    return &T->stack.level[T->stack.current_level];
+}
+tnsShader *tKnlGetActiveShader(){
+    return T->CurrentShader;
+}
+real *tnsGetModelMatrix(){
+    return tKnlGetCurrentMatStackItem()->model;
+}
+real *tnsGetViewMatrix(){
+    return tKnlGetCurrentMatStackItem()->view;
+}
+real *tnsGetProjectionMatrix(){
+    return tKnlGetCurrentMatStackItem()->projection;
+}
+void tnsGetMVMatrix(tnsMatrix44d r){
+    tnsMatrixStackItem *tmsi=tKnlGetCurrentMatStackItem();
+    tnsMatrix44d tmp;
+    tnsMultiply44d(r, tmsi->model, tmsi->view); 
+}
+void tnsGetMVPMatrix(tnsMatrix44d r){
+    tnsMatrixStackItem *tmsi=tKnlGetCurrentMatStackItem();
+    tnsMatrix44d tmp;
+    tnsMultiply44d(tmp, tmsi->model, tmsi->view); 
+    tnsMultiply44d(r, tmp, tmsi->projection); 
+}
+void tnsResetModelMatrix(){
+    tnsLoadIdentity44d(tnsGetModelMatrix());
+}
+void tnsResetViewMatrix(){
+    tnsLoadIdentity44d(tnsGetViewMatrix());
+}
+void tnsResetProjectionMatrix(){
+    tnsLoadIdentity44d(tnsGetProjectionMatrix());
+}
+int tKnlAttatchShader(tnsShader *tns){
+    lstAppendItem(&T->Shaders, tns);
+    tns->CustomID = T->NextShaderIndex;
+    T->NextShaderIndex++;
+    return tns->CustomID;
+};
+int CMP_NUM_IsThisShader(tnsShader *tns, int *index){
+    return (tns->CustomID == *index);
+}
+tnsShader *tKnlFindShader1i(int CustomIndex){
+    return lstFindItem(&CustomIndex, CMP_NUM_IsThisShader, &T->Shaders);
+}
+void tKnlPushMatrix(){
+    tnsMatrixStack *tms = &T->stack;
+    tnsShader *current_shader = tKnlGetActiveShader();
+
+    if (tms->current_level == tms->max_level || !current_shader) return;
+
+    memcpy(&tms->level[tms->current_level + 1], &tms->level[tms->current_level], sizeof(tnsMatrixStackItem));
+
+    tms->current_level++;
+
+    //tnsShaderApplyModel(current_shader,tms->level[tms->current_level].model);
+    //tnsShaderApplyView(current_shader,tms->level[tms->current_level].view);
+    //tnsShaderApplyProjection(current_shader,tms->level[tms->current_level].projection);
+};
+void tKnlPopMatrix(){
+    tnsMatrixStack *tms = &T->stack;
+    tnsShader *current_shader = tKnlGetActiveShader();
+
+    if (tms->current_level == 0 || !current_shader) return;
+
+    tms->current_level--;
+
+    tnsShaderApplyModel(current_shader, tms->level[tms->current_level].model);
+    tnsShaderApplyView(current_shader, tms->level[tms->current_level].view);
+    tnsShaderApplyProjection(current_shader, tms->level[tms->current_level].projection);
+}
+laListHandle *tKnlGetTextureList(){
+    return &T->Textures;
+}
+
+tnsBatch *tnsCreateBatch(u32bit NumVert, int Dimension, float *Data, int NormalDimension, float *Normal, int ColorDimension, float *Colors){
+    tnsBatch *b = CreateNew(tnsBatch);
+    b->Dimension = Dimension;
+    b->NormalDimension=NormalDimension;
+    b->ColorDimension=ColorDimension;
+    b->NumVert = NumVert;
+
+    glGenBuffers(1, &b->VBO);
+    glBindBuffer(GL_ARRAY_BUFFER, b->VBO);
+    glBufferData(GL_ARRAY_BUFFER, NumVert * Dimension * sizeof(GLfloat), Data, GL_DYNAMIC_DRAW);
+
+    if (Normal){
+        glGenBuffers(1, &b->NBO); glBindBuffer(GL_ARRAY_BUFFER, b->NBO);
+        glBufferData(GL_ARRAY_BUFFER, NumVert * NormalDimension * sizeof(GLfloat), Normal, GL_DYNAMIC_DRAW);
+        b->HasNormal=1;
+    }
+    if (Colors){
+        glGenBuffers(1, &b->CBO); glBindBuffer(GL_ARRAY_BUFFER, b->CBO);
+        glBufferData(GL_ARRAY_BUFFER, NumVert * ColorDimension * sizeof(GLfloat), Colors, GL_DYNAMIC_DRAW);
+        b->HasColor=1;
+    }
+
+    return b;
+}
+tnsBatch *tnsCreateBatchi(u32bit NumVert, int Dimension, int *Data){
+    tnsBatch *b = CreateNew(tnsBatch);
+    b->Dimension = Dimension;
+    b->NumVert = NumVert;
+
+    glGenBuffers(1, &b->VBO);
+    glBindBuffer(GL_ARRAY_BUFFER, b->VBO);
+    glBufferData(GL_ARRAY_BUFFER, NumVert * Dimension * sizeof(GLuint), Data, GL_DYNAMIC_DRAW);
+
+    return b;
+}
+void tnsCommandUseUniformColor(tnsBatchCommand*c, real* color){
+    tnsVectorCopy4d(color, c->UniformColor);
+    c->UseUniformColor=1;
+}
+void tnsCommandOverrideColorArray(tnsBatchCommand*c, int VertCount, int ColorDimension, float* colors){
+    if(!colors) return;
+    c->OverrideColorArray=1; 
+    glGenBuffers(1, &c->CBO); glBindBuffer(GL_ARRAY_BUFFER, c->CBO);
+    glBufferData(GL_ARRAY_BUFFER, VertCount* ColorDimension * sizeof(GLfloat), colors, GL_DYNAMIC_DRAW);
+    c->ColorDimension = ColorDimension;
+}
+tnsBatchCommand *tnsCreateCommand(tnsBatch *b, const char* name, u32bit ElementCount, int Dimension, GLenum DrawAs, u32bit *Elements, int HiddenByDefault){
+    tnsBatchCommand *bc = CreateNew(tnsBatchCommand);
+    bc->ElementCount = ElementCount;
+    bc->DrawAs = DrawAs;
+    bc->Dimension = Dimension;
+    bc->name=name;
+    bc->HiddenByDefault = HiddenByDefault;
+
+    if(Elements){
+        glGenBuffers(1, &bc->EBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bc->EBO);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, ElementCount * Dimension * sizeof(GLuint), Elements, GL_DYNAMIC_DRAW);
+        bc->DrawElements=1;
+    }else{ bc->EBO=-1; }
+    //int a = GetLastError();
+    lstAppendItem(&b->Branches, bc);
+
+    return bc;
+}
+void tnsDeleteBatch(tnsBatch *b){
+    tnsBatchCommand *bc, *NextBc;
+
+    glDeleteBuffers(1, &b->VBO);
+    if (b->NBO > -1) glDeleteBuffers(1, &b->NBO);
+    if (b->CBO > -1) glDeleteBuffers(1, &b->CBO);
+
+    for (bc = b->Branches.pFirst; bc; bc = NextBc){
+        NextBc = bc->Item.pNext;
+        lstRemoveItem(&b->Branches, bc);
+        if (bc->EBO > -1) glDeleteBuffers(1, &bc->EBO);
+        if (bc->CBO > -1) glDeleteBuffers(1, &bc->CBO);
+        FreeMem(bc);
+    }
+
+    FreeMem(b);
+}
+void tnsDrawBatch(tnsBatch* batch, const char* OverrideCommand, real* OverrideUniformColor, int OverrideAsArray) {
+	//int Mode = batch->DrawMode;
+	if (!batch) return;
+    tnsShader* cs=T->BindedShader;
+
+	//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
+
+	glBindBuffer(GL_ARRAY_BUFFER, batch->VBO);
+	glEnableVertexAttribArray(cs->iVertex);
+	glVertexAttribPointer(cs->iVertex, batch->Dimension, GL_FLOAT, 0, 0, 0);
+
+    if(cs->iNormal>=0){
+        if(batch->HasNormal){
+            glBindBuffer(GL_ARRAY_BUFFER, batch->NBO); glEnableVertexAttribArray(cs->iNormal);
+            glVertexAttribPointer(cs->iNormal, batch->NormalDimension, GL_FLOAT, 0, 0, 0);
+        }else{ glDisableVertexAttribArray(cs->iNormal); glVertexAttrib3f(cs->iNormal,0,0,1); }
+    }
+    if(cs->iColor>=0){
+        if(batch->HasColor){
+            glBindBuffer(GL_ARRAY_BUFFER, batch->CBO); glEnableVertexAttribArray(cs->iColor);
+            glVertexAttribPointer(cs->iColor, batch->ColorDimension, GL_FLOAT, 0, 0, 0);
+        }
+    }
+
+    int IsOverrideColor=0;
+	for (tnsBatchCommand* bc = batch->Branches.pFirst; bc; bc = bc->Item.pNext) {
+        if(OverrideCommand && !strSame(OverrideCommand, bc->name)){ continue; }
+        if(!OverrideCommand && bc->HiddenByDefault){ continue; }
+        if(cs->iColor){
+            if(bc->OverrideColorArray){
+                glBindBuffer(GL_ARRAY_BUFFER, bc->CBO); glEnableVertexAttribArray(cs->iColor);
+                glVertexAttribPointer(cs->iColor, bc->ColorDimension, GL_FLOAT, 0, 0, 0); IsOverrideColor=1;
+            }else{
+                if(batch->HasColor){ if(IsOverrideColor){ glBindBuffer(GL_ARRAY_BUFFER, batch->CBO); glEnableVertexAttribArray(cs->iColor);
+                    glVertexAttribPointer(cs->iColor, batch->ColorDimension, GL_FLOAT, 0, 0, 0); }
+                }else{ glDisableVertexAttribArray(cs->iColor); glVertexAttrib4fv(cs->iColor,T->StateColor); }
+            }
+            if(bc->UseUniformColor || OverrideUniformColor){ glDisableVertexAttribArray(cs->iColor); IsOverrideColor=1;
+                if(OverrideUniformColor){ glVertexAttrib4f(cs->iColor,LA_COLOR4(OverrideUniformColor)); }
+                else glVertexAttrib4f(cs->iColor,LA_COLOR4(bc->UniformColor)); 
+            }
+        }
+        int DrawElements=OverrideAsArray?0:bc->DrawElements;
+        if(DrawElements){
+            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bc->EBO);
+            glDrawElements(bc->DrawAs, bc->ElementCount*bc->Dimension, GL_UNSIGNED_INT, 0);
+        }else{ glDrawArrays(bc->DrawAs,0,bc->ElementCount); }
+	}
+
+	//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+//==========================*=======================[Texture]
+
+int tnsGetTextureMemoryComponetCount(tnsTexture *t){
+    int Comp = 0;
+    int CompSize;
+    switch (t->GLTexBitsType){
+    case GL_RGB:
+        Comp = 3;
+        break;
+    case GL_RGBA:
+        Comp = 4;
+        break;
+    }
+    return t->Width * t->Height * Comp;
+}
+
+int tnsInit2DTexture(tnsTexture *t, GLint glInternalFormat, int w, int h, int Multisample){
+    if (!t) return 0;
+
+    if(0/*glInternalFormat==GL_DEPTH_COMPONENT32F*/){
+        t->Width = w;
+        t->Height = h;
+        t->GLTexBitsType = GL_DEPTH_COMPONENT32F;
+        t->GLTexType = GL_RENDERBUFFER;
+        t->Multisample = Multisample;
+        glGenRenderbuffers(1, &t->GLTexHandle);
+        
+        tnsConfigureTexture(t);
+    }else{
+        t->Width = w;
+        t->Height = h;
+        t->GLTexBitsType = glInternalFormat;
+        t->GLTexType = Multisample?GL_TEXTURE_2D_MULTISAMPLE:GL_TEXTURE_2D;
+        t->Multisample = Multisample;
+        glGenTextures(1, &t->GLTexHandle);
+
+        tnsConfigureTexture(t);
+    }
+
+    return 1;
+}
+
+void tnsConfigureTexture(tnsTexture *t){
+    tnsBindTexture(t);
+    if(t->GLTexType==GL_RENDERBUFFER){
+        if(t->Multisample){ glRenderbufferStorageMultisample(GL_RENDERBUFFER, t->Multisample, t->GLTexBitsType, t->Width, t->Height); }
+        else { glRenderbufferStorage(GL_RENDERBUFFER, t->GLTexBitsType, t->Width, t->Height); }
+    }else{
+        int isDepth=t->GLTexBitsType==GL_DEPTH_COMPONENT||t->GLTexBitsType==GL_DEPTH_COMPONENT16||
+            t->GLTexBitsType==GL_DEPTH_COMPONENT24||t->GLTexBitsType==GL_DEPTH_COMPONENT32F;
+        int format=isDepth?GL_DEPTH_COMPONENT:GL_RGBA;
+        if(t->Multisample) glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, t->Multisample, t->GLTexBitsType, t->Width, t->Height, GL_TRUE);
+        else{ glTexImage2D(GL_TEXTURE_2D, 0, t->GLTexBitsType, t->Width, t->Height, 0, format, GL_UNSIGNED_BYTE, 0);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+                glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+                //glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+        }
+    }
+    tnsUnbindTexture(t);
+}
+
+void tnsReconfigureTextureParameters(int Multisample){
+    laListHandle* l = tKnlGetTextureList();
+    for(tnsOffscreen* o=T->Offscreens.pFirst;o;o=o->Item.pNext){
+        tnsTexture* t=o->pColor[0];
+        if(t){
+            t->Multisample = Multisample;
+            int recreate=0;
+            if(t->Multisample){ if(t->GLTexType==GL_TEXTURE_2D){t->GLTexType=GL_TEXTURE_2D_MULTISAMPLE; recreate=1;}}
+            else { if(t->GLTexType==GL_TEXTURE_2D_MULTISAMPLE){t->GLTexType=GL_TEXTURE_2D; recreate=1;}}
+            if(recreate){
+                glDeleteTextures(1, &t->GLTexHandle);
+                glGenTextures(1, &t->GLTexHandle);
+                T->TexColor=0;
+            }
+            tnsConfigureTexture(t);
+            tnsAttach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT0, t);
+        }
+        t=o->pDepth;
+        if(t){
+            t->Multisample = Multisample;
+            tnsConfigureTexture(t);
+            tnsAttach2DOffscreenBuffer(o, GL_DEPTH_ATTACHMENT, t);
+        }
+    }
+}
+
+tnsTexture *tnsCreate2DTexture(GLint glInternalFormat, int w, int h, int Multisample){
+    tnsTexture *tex = CreateNew(tnsTexture);
+    tnsInit2DTexture(tex, glInternalFormat, w, h, Multisample);
+    laNotifyUsers("tns.texture_list");
+    lstAppendItem(tKnlGetTextureList(), tex);
+    return tex;
+};
+void tnsCopyScreenTo2DTexture(tnsTexture *target, int x_lower_left, int y_lower_left, int w, int h){
+    if(target->GLTexType!=GL_TEXTURE_2D) return;
+    tnsBindTexture(target);
+    glReadBuffer(GL_BACK);
+    glCopyTexSubImage2D(target->GLTexType, 0, 0, 0, x_lower_left, y_lower_left, w, h);
+    tnsUnbindTexture();
+}
+
+void tnsUseMaskTexture(tnsTexture *t){
+    if(!t){T->StateTextureMode=0; return;}
+    T->StateTexColor = t; T->StateTextureMode=1;
+}
+void tnsUseTexture(tnsTexture *t){
+    if(!t){T->StateTextureMode=0; return;}
+    if(t->GLTexType == GL_TEXTURE_2D){ T->StateTexColor = t; T->StateTextureMode=2; }
+    else if(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ T->StateTexColor = t; T->StateTextureMode=3; }
+}
+void tnsUseNoTexture(){
+    tnsUseTexture(0);
+}
+void tnsUseMultiplyColor(int enable){
+    T->StateMultiplyColor=enable?1:0;
+}
+
+void tnsActiveTexture(GLenum tex){
+    if (T->GlTextureSets != tex) glActiveTexture(tex);
+    T->GlTextureSets = tex;
+}
+void tnsBindTexture(tnsTexture *t){
+    if (!t || T->TexColor==t) return;
+    if(t->GLTexType == GL_TEXTURE_2D){ tnsActiveTexture(GL_TEXTURE0); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
+    else if(t->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){ tnsActiveTexture(GL_TEXTURE1); glBindTexture(t->GLTexType, t->GLTexHandle); T->TexColor=t;}
+    else if(t->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle); T->TexRenderbuffer = t;}
+}
+void tnsUnbindTexture(){
+    if(T->TexRenderbuffer){ if(T->TexRenderbuffer->GLTexType == GL_RENDERBUFFER){ glBindRenderbufferEXT(GL_RENDERBUFFER, 0); T->TexRenderbuffer=0;}}
+    if(T->TexColor){
+        if(T->TexColor->GLTexType == GL_TEXTURE_2D){tnsActiveTexture(GL_TEXTURE0);}
+        else if(T->TexColor->GLTexType == GL_TEXTURE_2D_MULTISAMPLE){tnsActiveTexture(GL_TEXTURE1);}
+        glBindTexture(T->TexColor->GLTexType, 0); T->TexColor=0;
+    }
+}
+void tnsUniformUseTexture(tnsShader* s, int mode, int sample){
+    if(s->StateTextureMode != mode){ s->StateTextureMode=mode; glUniform1i(s->iTextureMode,mode); }
+    if(mode==3 && s->StateSampleAmount != sample){ s->StateSampleAmount=sample, glUniform1i(s->iSampleAmount,sample); }
+}
+void tnsUniformUseMultiplyColor(tnsShader* s, int enable){
+    int mode=enable?1:0;
+    if(s->StateMultiplyColor != mode){ s->StateMultiplyColor=mode; glUniform1i(s->iMultiplyColor,mode); }
+}
+
+void tnsDraw2DTextureDirectly(tnsTexture *t, real x, real y, real w, real h){
+    real Verts[8];
+    real UV[8] = {
+        0.0f, 1.0f,
+        1.0f, 1.0f,
+        1.0f, 0.0f,
+        0.0f, 0.0f};
+    tnsMakeQuad2d(Verts, x, y, x + w, y, x + w, y + h, x, y + h);
+    tnsUseTexture(t);
+    tnsVertexArray2d(Verts, 4);
+    tnsTexCoordArray2d(UV, 4);
+    tnsPackAs(GL_TRIANGLE_FAN);
+}
+void tnsDraw2DTextureArg(tnsTexture *t,
+                         real x_upper_right, real y_upper_right, int w, int h,
+                         real *MultiplyColor,
+                         real LPadding, real RPadding, real TPadding, real BPadding){
+    real Verts[8];
+    real UV[8] = {
+        0.0f + LPadding, 1.0f - TPadding,
+        1.0f - RPadding, 1.0f - TPadding,
+        1.0f - RPadding, 0.0f + BPadding,
+        0.0f + LPadding, 0.0f + BPadding};
+    tnsMakeQuad2d(Verts,
+                  x_upper_right, y_upper_right,
+                  x_upper_right + w, y_upper_right,
+                  x_upper_right + w, y_upper_right + h,
+                  x_upper_right, y_upper_right + h);
+
+    if (MultiplyColor){ tnsColor4dv(MultiplyColor); tnsUseMultiplyColor(1); }
+
+    tnsUseTexture(t);
+    tnsVertexArray2d(Verts, 4);
+    tnsTexCoordArray2d(UV, 4);
+    tnsPackAs(GL_TRIANGLE_FAN);
+    tnsUseMultiplyColor(0);
+}
+void tnsDeleteTexture(tnsTexture *t){
+    laListHandle *lst = tKnlGetTextureList();
+
+    tnsUnbindTexture();
+
+    if (!t) return;
+
+    if (t->GLTexType == GL_RENDERBUFFER){
+        glBindRenderbufferEXT(GL_RENDERBUFFER, t->GLTexHandle);
+        glDeleteRenderbuffersEXT(1, &t->GLTexHandle);
+    }else{
+        //glBindTexture(t->GLTexType, 0);
+        glDeleteTextures(1, &t->GLTexHandle);
+    }
+    laNotifyUsers("tns.texture_list");
+    lstRemoveItem(lst, t);
+    if (t->DrawData) FreeMem(t->DrawData);
+    FreeMem(t);
+}
+
+int tnsTextureMemorySize(tnsTexture *t, int Mem){
+    int ElemSize;
+
+    if (Mem) return t->Width * t->Height * sizeof(void *);
+
+    switch (t->GLTexBitsType){
+    default:
+    case GL_RED:
+        ElemSize = sizeof(char) * 1;
+        break;
+    case GL_RG:
+        ElemSize = sizeof(char) * 2;
+        break;
+    case GL_RGB:
+        ElemSize = sizeof(char) * 3;
+        break;
+    case GL_RGBA:
+        ElemSize = sizeof(char) * 4;
+        break;
+    case GL_RGBA32F:
+        ElemSize = sizeof(float) * 4;
+        break;
+    case GL_DEPTH_COMPONENT32F:
+        ElemSize = sizeof(float);
+        break;
+    }
+
+    t->ElemSize = ElemSize;
+
+    return t->Width * t->Height * ElemSize;
+}
+
+void tnsCreateTextureReadbackBuffer(tnsTexture *t){
+    if (t->SamplePtr){
+        tnsTextureSample *tns;
+        memset(t->SamplePtr, 0, tnsTextureMemorySize(t, 1));
+        while (tns = lstPopItem(&t->ErasedSamples))
+            FreeMem(tns);
+        while (tns = lstPopItem(&t->PendingSamples))
+            FreeMem(tns);
+    }else{
+        t->TextureReadBack = calloc(1, tnsTextureMemorySize(t, 0));
+        t->SamplePtr = calloc(1, tnsTextureMemorySize(t, 1));
+    }
+    t->RBWidth = t->Width;
+    t->RBHeight = t->Height;
+}
+void tnsDeleteTextureReadbackBuffer(tnsTexture *t){
+    FreeMem(t->TextureReadBack);
+    FreeMem(t->SamplePtr);
+    tnsTextureSample *tns;
+    while (tns = lstPopItem(&t->ErasedSamples))
+        FreeMem(tns);
+    while (tns = lstPopItem(&t->PendingSamples))
+        FreeMem(tns);
+    t->RBWidth = t->RBHeight = 0;
+}
+void tnsReadbackTexture(tnsTexture *t){
+    //if (t->RBWidth != t->Width || t->RBHeight != t->Height) tnsDeleteTextureReadbackBuffer(t);
+//
+    //tnsCreateTextureReadbackBuffer(t);
+//
+    //tnsBindTexture(t);
+    //glGetTexImage(t->GLTexType, 0, t->DataFormat, t->DataType, t->TextureReadBack);
+    //tnsUnbindTexture();
+//
+    //int w, h;
+    //tnsTextureSample *tns;
+    //u8bit sample;
+    //for (h = 0; h < t->Height; h++){
+    //    for (w = 0; w < t->Width; w++){
+    //        int index = h * t->Width + w;
+    //        if ((sample = *tnsTextureSampleU8(t, w, h)) > TNS_SNAKE_STRENGTH_LIMIT){
+    //            tns = CreateNew(tnsTextureSample);
+    //            lstAppendItem(&t->PendingSamples, tns);
+    //            t->SamplePtr[h * t->Width + w] = tns;
+    //            tns->X = w;
+    //            tns->Y = h;
+    //            tns->Sample = sample;
+    //        }
+    //    }
+    //}
+}
+
+//====================================================[NEW RENDER KERNEL]
+//=================[Immediate-style api]
+
+void tnsColor4d(real r, real g, real b, real a){
+    T->StateColor[0] = r;
+    T->StateColor[1] = g;
+    T->StateColor[2] = b;
+    T->StateColor[3] = a;
+}
+void tnsColor4dv(real *rgba){
+    T->StateColor[0] = rgba[0];
+    T->StateColor[1] = rgba[1];
+    T->StateColor[2] = rgba[2];
+    T->StateColor[3] = rgba[3];
+}
+
+void tnsPolygonMode(GLenum PolyMode){
+    T->StatePolyMode = PolyMode;
+}
+void tnsShadeMode(GLenum ShadeMode){
+    T->StateShadeMode = ShadeMode;
+}
+void tnsVertex3d(real x, real y, real z){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    short vend = c->VertEnd;
+
+    c->UseVert = 1;
+
+    if (!c->Dimensions) c->Dimensions = 3;
+
+    if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions, &T->MaxVert, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *varr = T->Vert;
+    if (c->Dimensions == 3){
+        varr[vend] = x;
+        varr[vend + 1] = y;
+        varr[vend + 2] = z;
+        c->NumVert++;
+        T->NextVert += 3;
+        c->VertEnd += 3;
+    }else{
+        varr[vend] = x;
+        varr[vend + 1] = y;
+        c->NumVert++;
+        T->NextVert += 2;
+        c->VertEnd += 2;
+    }
+}
+void tnsVertex2d(real x, real y){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    short vend = c->VertEnd;
+
+    c->UseVert = 1;
+
+    if (!c->Dimensions) c->Dimensions = 2;
+    
+    if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions, &T->MaxVert, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *varr = T->Vert;
+    if (c->Dimensions == 2){
+        varr[vend] = x;
+        varr[vend + 1] = y;
+        c->NumVert++;
+        T->NextVert += 2;
+        c->VertEnd += 2;
+    }else{
+        tnsVertex3d(x, y, 0.0f);
+    }
+}
+void tnsVertexArray2d(real *verts, int amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    int trans = 2 * amount;
+    short vend = c->VertEnd;
+
+    c->UseVert = 1;
+
+    if (!c->Dimensions) c->Dimensions = 2;
+
+    if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions*amount, &T->MaxVert, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *varr = T->Vert;
+    if (c->Dimensions == 2){
+        int i;
+        for (i = 0; i < trans; i++){
+            varr[vend] = verts[i];
+            vend++;
+        }
+        //memcpy(&varr[vend], verts, trans*sizeof(real));
+        c->VertEnd += trans;
+        c->NumVert += amount;
+        T->NextVert += trans;
+    }
+}
+void tnsVertexArray3d(real *verts, int amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    int trans = 3 * amount;
+    short vend = c->VertEnd;
+
+    c->UseVert = 1;
+
+    if (!c->Dimensions) c->Dimensions = 3;
+
+    if(arrEnsureLength(&T->Vert, T->NextVert+c->Dimensions*amount, &T->MaxVert, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxVert * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *varr = T->Vert;
+    if (c->Dimensions == 3){
+        int i;
+        for (i = 0; i < trans; i++){
+            varr[vend] = verts[i];
+            vend++;
+        }
+        //memcpy(&varr[vend], verts, trans*sizeof(real));
+        c->VertEnd += trans;
+        c->NumVert += amount;
+        T->NextVert += trans;
+    }
+}
+void tnsColorArray4d(real *colors, int amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    int trans = 4 * amount;
+    int ofst = c->ColorEnd;
+
+    c->UseColor = 1;
+
+    if(arrEnsureLength(&T->Color, T->NextColor+4*amount, &T->MaxColor, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxColor * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *carr = T->Color;
+    int i;
+    for (i = 0; i < trans; i++){
+        carr[ofst] = colors[i];
+        ofst++;
+    }
+    //memcpy(&T->Color[c->ColorEnd], colors, trans*sizeof(real));
+    c->ColorEnd += trans;
+    T->NextColor += trans;
+}
+void tnsNormalArray3d(real *normals, int amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    int trans = 3 * amount;
+    int ofst = c->NormalEnd;
+
+    c->UseNormal = 1;
+
+    if(arrEnsureLength(&T->Normal, T->NextNormal+3*amount, &T->MaxNormal, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxNormal * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *narr = T->Normal;
+    int i;
+    for (i = 0; i < trans; i++){
+        narr[ofst] = normals[i];
+        ofst++;
+    }
+    //memcpy(&T->Normal[c->NormalEnd], normals, trans*sizeof(real));
+    c->NormalEnd += trans;
+    T->NextNormal += trans;
+}
+void tnsTexCoordArray2d(real *coords, int amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    int trans = 2 * amount;
+    int ofst = c->TexCoordEnd;
+
+    c->UseTexCoord = 1;
+    c->UVDimensions = 2;
+
+    if(arrEnsureLength(&T->TexCoord, T->NextTexCoord+2*amount, &T->MaxTexCoord, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxTexCoord * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *carr = T->TexCoord;
+    int i;
+    for (i = 0; i < trans; i++){
+        carr[ofst] = coords[i];
+        ofst++;
+    }
+    //memcpy(&T->TexCoord[c->TexCoordEnd], coords, trans*sizeof(real));
+    c->TexCoordEnd += trans;
+    T->NextTexCoord += trans;
+}
+void tnsTexCoordArray3d(real *coords, int amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    int trans = 3 * amount;
+    int ofst = c->TexCoordEnd;
+
+    c->UseTexCoord = 1;
+    c->UVDimensions = 3;
+
+    if(arrEnsureLength(&T->TexCoord, T->NextTexCoord+3*amount, &T->MaxTexCoord, sizeof(GLfloat))){
+        glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
+        glBufferData(GL_ARRAY_BUFFER, T->MaxTexCoord * sizeof(GLfloat), 0, GL_DYNAMIC_DRAW);
+    }
+
+    GLfloat *carr = T->TexCoord;
+    int i;
+    for (i = 0; i < trans; i++){ carr[ofst] = coords[i]; ofst++; }
+    c->TexCoordEnd += trans;
+    T->NextTexCoord += trans;
+}
+void tnsIndexArray(GLuint *index, short amount){
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+
+    //if (c->UseIndex) return;
+    c->UseIndex = 1;
+
+    if(arrEnsureLength(&T->Index, T->NextIndex+amount, &T->MaxIndex, sizeof(GLuint))){
+        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, T->IndexBufObject);
+        glBufferData(GL_ELEMENT_ARRAY_BUFFER, T->MaxIndex * sizeof(GLuint), 0, GL_DYNAMIC_DRAW);
+    }
+
+    memcpy(&T->Index[c->IndexEnd], index, amount * sizeof(GLuint));
+    c->IndexEnd += amount;
+    c->NumIndex += amount;
+    T->NextIndex += amount;
+}
+
+void tnsPackAs(GLenum Mode){
+    arrEnsureLength(&T->DrawingCommand, T->NextCommand+1, &T->MaxCommand, sizeof(tnsCommand));
+    tnsCommand *c = &T->DrawingCommand[T->NextCommand];
+    tnsCommand *nc;
+
+    T->NextCommand++;
+    nc = &T->DrawingCommand[T->NextCommand];
+
+    memcpy(c->UniformColor, T->StateColor, sizeof(GLfloat) * 4);
+
+    if (Mode == GL_QUAD_STRIP || Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP;
+    //if (Mode == GL_QUADS) Mode=GL_TRIANGLE_STRIP;
+    c->Mode = Mode;
+    c->ReplaceShader = T->StateShader;
+    c->PolyMode = T->StatePolyMode;
+    c->Shade = T->StateShadeMode;
+    c->ColorTexture = T->StateTexColor;
+    c->TextureMode = T->StateTextureMode;
+    c->MultiplyColor = T->StateMultiplyColor;
+
+    memset(nc, 0, sizeof(tnsCommand));
+    nc->VertBegin = nc->VertEnd = c->VertEnd;
+    nc->NormalBegin = nc->NormalEnd = c->NormalEnd;
+    nc->ColorBegin = nc->ColorEnd = c->ColorEnd;
+    nc->TexCoordBegin = nc->TexCoordEnd = c->TexCoordEnd;
+    nc->IndexBegin = nc->IndexEnd = c->IndexEnd;
+}
+void tnsFlush(){
+    tnsShader *cs = T->CurrentShader;
+    tnsCommand *tc = &T->DrawingCommand[0];
+    tnsCommand *c = tc;
+    int PrevDimensions = 0;
+    int LastVertBegin = 0;
+
+    if (!c || !cs) return;
+
+    if (T->NextVert){
+        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+        //glEnableVertexAttribArray(cs->iVertex);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextVert * sizeof(GLfloat), T->Vert);
+    }
+    if (T->NextColor){
+        glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject);
+        //glEnableVertexAttribArray(cs->iColor);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextColor * sizeof(GLfloat), T->Color);
+    }
+    if (T->NextNormal){
+        glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject);
+        //glEnableVertexAttribArray(cs->iColor);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextNormal * sizeof(GLfloat), T->Normal);
+    }
+    if (T->NextTexCoord){
+        glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
+        //glEnableVertexAttribArray(cs->iColor);
+        glBufferSubData(GL_ARRAY_BUFFER, 0, T->NextTexCoord * sizeof(GLfloat), T->TexCoord);
+    }
+
+    for (int i=0;i<T->NextCommand;i++){
+        c=&T->DrawingCommand[i];
+
+        if (c->PolyMode != T->StatePolyMode){glPolygonMode(GL_FRONT_AND_BACK, c->PolyMode); T->StatePolyMode=c->PolyMode;}
+        if (c->Shade != T->StateShadeMode){glShadeModel(c->Shade); T->StateShadeMode=c->Shade;}
+        if (c->ReplaceShader && c->ReplaceShader != T->CurrentShader){
+            tnsEnableShaderv(c->ReplaceShader);
+            cs = c->ReplaceShader;
+            if (!cs) continue;
+        }
+
+        glBindBuffer(GL_ARRAY_BUFFER, T->VertBufObject);
+        if (c->UseVert){
+            glEnableVertexAttribArray(cs->iVertex);
+            glVertexAttribPointer(cs->iVertex, (c->Dimensions ? c->Dimensions : PrevDimensions),
+                                  GL_FLOAT, 0, 0, c->VertBegin * sizeof(GLfloat));
+            LastVertBegin = c->VertBegin;
+        }else{
+            glEnableVertexAttribArray(cs->iVertex);
+            glVertexAttribPointer(cs->iVertex, (c->Dimensions ? c->Dimensions : PrevDimensions),
+                                  GL_FLOAT, 0, 0, LastVertBegin * sizeof(GLfloat));
+        }
+
+        PrevDimensions = (c->Dimensions ? c->Dimensions : PrevDimensions);
+
+        if (c->UseIndex){
+            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, T->IndexBufObject);
+            glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, c->NumIndex * sizeof(GLuint), &T->Index[c->IndexBegin]);
+        }
+
+        if (cs->iNormal != -1){
+            glBindBuffer(GL_ARRAY_BUFFER, T->NormalBufObject);
+            if (c->UseNormal){
+                glEnableVertexAttribArray(cs->iNormal);
+            }
+            glVertexAttribPointer(cs->iNormal, 3, GL_FLOAT, 0, 0, c->NormalBegin * sizeof(GLfloat));
+            if (!c->UseNormal && c->Dimensions == 2){
+                glDisableVertexAttribArray(cs->iNormal);
+                glVertexAttrib3f(cs->iNormal, 0, 0, -1);
+            }
+        }
+
+        if (cs->iColor != -1){
+            glBindBuffer(GL_ARRAY_BUFFER, T->ColorBufObject);
+            if (c->UseColor){
+                glEnableVertexAttribArray(cs->iColor);
+                glVertexAttribPointer(cs->iColor, 4, GL_FLOAT, 0, 0, c->ColorBegin * sizeof(GLfloat));
+            }else{
+                glDisableVertexAttribArray(cs->iColor);
+                glVertexAttrib4fv(cs->iColor, c->UniformColor);
+            }
+        }
+
+        if (cs->iUV != -1){
+            if (c->UseTexCoord){
+                glBindBuffer(GL_ARRAY_BUFFER, T->TexCoordBufObject);
+                if (c->UseTexCoord){ glEnableVertexAttribArray(cs->iUV);
+                    glVertexAttribPointer(cs->iUV, c->UVDimensions, GL_FLOAT, 0, 0, c->TexCoordBegin * sizeof(GLfloat)); }
+                else{ glDisableVertexAttribArray(cs->iUV); }
+            }
+        }
+
+        if (c->TextureMode && c->ColorTexture && cs->iTexColor != -1){
+            tnsBindTexture(c->ColorTexture); tnsUniformUseTexture(cs, c->TextureMode, c->ColorTexture->Multisample);
+        }else{
+            tnsUniformUseTexture(cs, 0, 0); //tnsUnbindTexture(); 
+        }
+
+        if(cs->iMultiplyColor != -1){
+            tnsUniformUseMultiplyColor(cs, c->MultiplyColor);
+        }
+
+        if (c->UseIndex){
+            glDrawElements(c->Mode, c->NumIndex, GL_UNSIGNED_INT, 0);
+        }else{
+            glDrawArrays(c->Mode, 0, c->NumVert);
+        }
+    }
+
+    T->NextCommand=0;
+    c = &T->DrawingCommand[0];
+
+    memset(c, 0, sizeof(tnsCommand));
+
+    c->ColorBegin = c->ColorEnd = T->NextColor = 0;
+    c->NormalBegin = c->NormalEnd = T->NextNormal = 0;
+    c->TexCoordBegin = c->TexCoordEnd = T->NextTexCoord = 0;
+    c->VertBegin = c->VertEnd = T->NextVert = 0;
+    c->IndexBegin = c->IndexEnd = T->NextIndex = 0;
+
+    //must --why?
+    //T->BindedShader = 0;
+};
+
+//============================================================================================[offscr]
+
+const GLuint TNS_ATTACHMENT_ARRAY_NONE[] = {GL_NONE};
+const GLuint TNS_ATTACHMENT_ARRAY[] = {GL_COLOR_ATTACHMENT0};
+const GLuint TNS_ATTACHMENT_ARRAY_1[] = {GL_COLOR_ATTACHMENT1};
+const GLuint TNS_ATTACHMENT_ARRAY_2[] = {GL_COLOR_ATTACHMENT2};
+const GLuint TNS_ATTACHMENT_ARRAY_1_2[] = {GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
+const GLuint TNS_ATTACHMENT_ARRAY_0_1_2[] = {GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2};
+const GLenum TNS_WINDOW_DRAWBUFFER_ARRAY[] = {GL_BACK};
+
+tnsOffscreen *tnsCreateOffscreenHandle(){
+    tnsOffscreen *toff = CreateNew(tnsOffscreen);
+    glGenFramebuffers(1, &toff->FboHandle);
+    lstAppendItem(&T->Offscreens, toff);
+    return toff;
+}
+void tnsAttach2DOffscreenBuffer(tnsOffscreen *target, GLuint attatchment, tnsTexture *use){
+    if (!target || !use || target->FboHandle == -1 || use->GLTexHandle == -1) return;
+
+    if (attatchment >= GL_COLOR_ATTACHMENT0 && attatchment <= GL_COLOR_ATTACHMENT15){
+        //if (target->pColor[attatchment - GL_COLOR_ATTACHMENT0]) return;
+
+        glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle);
+        tnsBindTexture(use);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, attatchment, use->GLTexType, use->GLTexHandle, 0);
+        target->pColor[attatchment - GL_COLOR_ATTACHMENT0] = use;
+        tnsUnbindTexture();
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    }elif (attatchment == GL_DEPTH_ATTACHMENT){
+        //if (target->pDepth) return;
+        glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle);
+        tnsBindTexture(use);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, attatchment, use->GLTexType, use->GLTexHandle, 0);
+        //glBindRenderbufferEXT(GL_RENDERBUFFER, use->GLTexHandle);
+        //glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle);
+        //glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, use->GLTexHandle);
+        target->pDepth = use;
+        tnsUnbindTexture();
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        //glBindRenderbufferEXT(GL_RENDERBUFFER, 0);
+        //glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    }
+    GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+    //if (result == GL_FRAMEBUFFER_COMPLETE) {
+    //	printf("Framebuffer complete!\n");
+    //}
+    //else {
+    //	printf("Framebuffer incomplete!\n");
+    //}
+}
+void tnsDetach2DOffscreenBuffer(tnsOffscreen *target, GLuint which_attach_point){
+    if (which_attach_point >= GL_COLOR_ATTACHMENT0 && which_attach_point <= GL_COLOR_ATTACHMENT15){
+        if (target->pColor[which_attach_point - GL_COLOR_ATTACHMENT0] == 0) return;
+
+        glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, which_attach_point, GL_TEXTURE_2D, 0, 0);
+
+        tnsDeleteTexture(target->pColor[which_attach_point - GL_COLOR_ATTACHMENT0]);
+
+        target->pColor[which_attach_point - GL_COLOR_ATTACHMENT0] = 0;
+    }elif (which_attach_point == GL_DEPTH_ATTACHMENT){
+        if (target->pDepth) return;
+
+        glBindFramebuffer(GL_FRAMEBUFFER, target->FboHandle);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, 0, 0);
+
+        tnsDeleteTexture(target->pDepth);
+
+        target->pDepth = 0;
+    }
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    tnsUnbindTexture();
+}
+
+tnsOffscreen *tnsCreate2DOffscreen(int glInternalFormat, int w, int h, int Multisample, int WithDepth){
+    tnsOffscreen *toff = tnsCreateOffscreenHandle();
+    tnsTexture *color;
+    tnsTexture *depth;
+
+    if(glInternalFormat){
+        color = tnsCreate2DTexture(glInternalFormat, w, h, Multisample);
+        tnsAttach2DOffscreenBuffer(toff, GL_COLOR_ATTACHMENT0, color);
+    }
+    if(WithDepth){
+        depth = tnsCreate2DTexture(GL_DEPTH_COMPONENT, w, h, Multisample);
+        tnsAttach2DOffscreenBuffer(toff, GL_DEPTH_ATTACHMENT, depth);
+    }
+
+    return toff;
+}
+
+void tnsConfigureOffscreen(tnsOffscreen *off, int w, int h){
+    tnsTexture* t=off->pColor[0];
+    t->Width = w; t->Height = h; tnsConfigureTexture(t);
+    t=off->pDepth;
+    if(t){
+        t->Width = w; t->Height = h; tnsConfigureTexture(t);
+    }
+}
+
+void tnsDelete2DOffscreen(tnsOffscreen *o){
+    if (!o) return;
+
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+
+    if (o->pColor[1]){
+        tnsDetach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT1);
+        tnsDeleteTexture(o->pColor[1]);
+    }
+    if (o->pColor[2]){
+        tnsDetach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT2);
+        tnsDeleteTexture(o->pColor[2]);
+    }
+    if (o->pColor[3]){
+        tnsDetach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT3);
+        tnsDeleteTexture(o->pColor[3]);
+    }
+
+    tnsDetach2DOffscreenBuffer(o, GL_COLOR_ATTACHMENT0);
+    tnsDetach2DOffscreenBuffer(o, GL_DEPTH_ATTACHMENT);
+
+    tnsDeleteTexture(o->pColor[0]);
+    tnsDeleteTexture(o->pDepth);
+
+    glDeleteFramebuffers(1, &o->FboHandle);
+    //tnsDeleteTexture(o->pStencil);
+
+    lstRemoveItem(&T->Offscreens, o);
+    FreeMem(o);
+}
+
+void tnsDrawToOffscreen(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray){
+    if (!toff) return;
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
+    if(AttachmentArray==TNS_ATTACHMENT_ARRAY_NONE){glDrawBuffer(GL_NONE);}
+    else glDrawBuffers((HowMany ? HowMany : 1), (AttachmentArray ? AttachmentArray : TNS_ATTACHMENT_ARRAY));
+    T->IsOffscreen = 1;
+    T->BindedShader = 0;
+}
+//void tnsDrawToExtraColorAttachment(tnsOffscreen *toff){
+//    if (!toff) return;
+//    if (!toff->pColor[1]){
+//        tnsCreate2DOffscreenMSAttachmentExtraColor(toff);
+//    }
+//    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
+//    glDrawBuffers(1, TNS_ATTACHMENT_ARRAY_1);
+//    T->IsOffscreen = 1;
+//    T->BindedShader = 0;
+//}
+//void tnsDrawToExtraNormalAttachment(tnsOffscreen *toff){
+//    if (!toff) return;
+//    if (!toff->pColor[2]){
+//        tnsCreate2DOffscreenMSAttachmentExtraNormal(toff);
+//    }
+//    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
+//    glDrawBuffers(1, TNS_ATTACHMENT_ARRAY_2);
+//    T->IsOffscreen = 1;
+//    T->BindedShader = 0;
+//}
+//void tnsDrawToAllExtraAttachments(tnsOffscreen *toff){
+//    if (!toff) return;
+//    if (!toff->pColor[1]){
+//        tnsCreate2DOffscreenMSAttachmentExtraColor(toff);
+//    }
+//    if (!toff->pColor[2]){
+//        tnsCreate2DOffscreenMSAttachmentExtraNormal(toff);
+//    }
+//    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
+//    glDrawBuffers(2, TNS_ATTACHMENT_ARRAY_1_2);
+//    T->IsOffscreen = 1;
+//    T->BindedShader = 0;
+//}
+void tnsDrawToOffscreenOnlyBind(tnsOffscreen *toff, int HowMany, GLuint *AttachmentArray){
+    if (!toff) return;
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, toff->FboHandle);
+}
+void tnsReadFromOffscreen(tnsOffscreen *toff){
+    if (!toff) return;
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, toff->FboHandle);
+}
+void tnsPassColorBetweenOffscreens(tnsOffscreen *from, tnsOffscreen *to,
+                                   GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLenum FilterMode){
+    if (!from || !to) return;
+    glBlitFramebufferEXT(
+        srcX0, srcY0, srcX1, srcY1,
+        dstX0, dstY0, dstX1, dstY1,
+        GL_COLOR_BUFFER_BIT, FilterMode);
+}
+void tnsDrawToScreen(){
+    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+    glDrawBuffer(GL_BACK);
+    T->IsOffscreen = 0;
+    T->BindedShader = 0;
+}
+
+//===========================================================================[FONT]
+
+tnsFontManager *FM;
+
+void tnsSetuptnsFontManager(){
+    FM = CreateNew(tnsFontManager);
+};
+
+int next_p2(int a){
+    int rval = 1;
+    while (rval < a)
+        rval <<= 1;
+    return rval;
+}
+int tnsGetMonoFontAdvance(){
+    return FM->UsingFont->MonoAdvance;
+}
+int tnsInvalidateFontCache(){
+    tnsFont*f=FM->UsingFont;
+    for(int i=0;i<TNS_UNICODE_COUNT;i++){ if(f->characters){ free(f->characters[i]); f->characters[i]=0; } }
+    for(int i=0;i<TNS_MONO_COUNT;i++){ if(f->monocharacters){ free(f->monocharacters[i]); f->monocharacters[i]=0; } }
+    f->CurrentX=f->CurrentY=0;
+    f->height = LA_RH*(MAIN.FontSize/2.0f+0.5f);
+    int GenHeight=LA_RH*MAIN.FontSize;
+    for(int i=0;i<f->NumFaces;i++){
+        FT_Set_Char_Size(f->ftface[i], 0, GenHeight << 6, 96, 96);
+    }
+    if(f->ftfacemono){
+        FT_Set_Char_Size(f->ftfacemono, 0, (GenHeight << 6)*f->MonoScale, 96, 96); FT_Glyph glyph;
+        if (FT_Load_Char(f->ftfacemono, 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)||
+            FT_Get_Glyph(f->ftfacemono->glyph, &glyph)){ SEND_PANIC_ERROR("Monospace font doesn't contain character 'a'"); }
+        f->MonoAdvance=f->ftfacemono->glyph->advance.x/64.0;
+    }
+}
+tnsFontSingleCharacter *tfntFetchCharTextureIDW(uint32_t ch, int UseMono);
+void tnsLoadSystemFontMono(char* mono){
+    if(!FM->UsingFont || !mono || !mono[0]) return;
+    tnsFont *f=FM->UsingFont;
+    
+    int GenHeight=LA_RH*MAIN.FontSize;
+
+    int full_adv=0,half_adv=0;
+    for(int i=0;i<f->NumFaces;i++){
+        if(!FT_Get_Advance(f->ftface[i],L'我',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &full_adv)) break;
+    }
+
+    if (FT_New_Face(f->ftlib, mono, 0, &f->ftfacemono)) SEND_PANIC_ERROR("Freetype Can't Init Face");
+    FT_Select_Charmap(f->ftfacemono, FT_ENCODING_UNICODE);
+    FT_Set_Char_Size(f->ftfacemono, 0, GenHeight << 6, 96, 96);
+    if(!FT_Get_Advance(f->ftfacemono,'a',FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP, &half_adv)){
+        f->MonoScale=(real)full_adv/(half_adv*2);
+        FT_Set_Char_Size(f->ftfacemono, 0, (GenHeight << 6)*f->MonoScale, 96, 96);
+        logPrint("Monospace font scale: %.2f\n",f->MonoScale); FT_Glyph glyph;
+        if (FT_Load_Char(f->ftfacemono, 'a', FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)||
+            FT_Get_Glyph(f->ftfacemono->glyph, &glyph)){ SEND_PANIC_ERROR("Monospace font doesn't contain character 'a'"); }
+        f->MonoAdvance=f->ftfacemono->glyph->advance.x/64.0;
+    }
+};
+void tnsLoadSystemFont(int num_fonts, ...){
+    char * name;
+
+    tnsFont *f = CreateNew(tnsFont);
+    f->characters=calloc(1, sizeof(tnsFontSingleCharacter*)*TNS_UNICODE_COUNT);
+    f->monocharacters=calloc(1, sizeof(tnsFontSingleCharacter*)*TNS_MONO_COUNT);
+
+    f->height = LA_RH*(MAIN.FontSize/2.0f+0.5f);
+    int GenHeight=LA_RH*MAIN.FontSize;
+
+    if (FT_Init_FreeType(&f->ftlib)) SEND_PANIC_ERROR("Freetype Init Failed!");
+
+    if(num_fonts>=16){num_fonts=16;}
+    va_list fn;
+    va_start(fn, num_fonts);
+    for(int i=0;i<num_fonts;i++){
+        name = va_arg(fn, char*);
+        if (name && FT_New_Face(f->ftlib, name, 0, &f->ftface[i])) SEND_PANIC_ERROR("Freetype Can't Init Face");
+        FT_Select_Charmap(f->ftface[i], FT_ENCODING_UNICODE);
+        FT_Set_Char_Size(f->ftface[i], 0, GenHeight << 6, 96, 96);
+    }
+    va_end(fn);
+    f->NumFaces = num_fonts;
+    
+    tnsInit2DTexture(&f->TexBuffer, GL_RED, TNS_FONT_BUFFER_W, TNS_FONT_BUFFER_H, 0);
+    
+    lstAppendItem(&FM->Fonts, f);
+    tnsUseFont(0);
+};
+int tnsLoadVectorGraphPackage(const char *name, unsigned int size){
+    char i;
+
+    tnsFont *f = CreateNew(tnsFont);
+
+    f->height = (int)((real)size * 1.4);
+    f->fontName = name;
+
+    if (FT_Init_FreeType(&f->ftlib)) SEND_PANIC_ERROR("Can't Load Main Font:Freetype Init Failed!");
+    if (FT_New_Face(f->ftlib, name, 0, &f->ftface)) SEND_PANIC_ERROR("Can't Load Main Font:Freetype Can't Init Face");
+
+    FT_Select_Charmap(f->ftface, FT_ENCODING_UNICODE);
+    FT_Set_Char_Size(f->ftface, size << 6, size << 6, 96, 96);
+
+    //tnsInit2DTexture(&f->TexBuffer, GL_ALPHA, TNS_FONT_BUFFER_W, TNS_FONT_BUFFER_H, 0);
+
+    //lstAppendItem(&FM->Fonts, f);
+
+    //tnsUseFont(name);
+
+    FM->VectorsGrapghs = f;
+};
+
+int tfntBufferWidthEnough(int total_width, int current_width, int this_width){
+    return (current_width + this_width < total_width);
+}
+
+void tfntApplyCharacterBufferOffset(tnsFont *f, tnsFontSingleCharacter *fsc){
+    if (!tfntBufferWidthEnough(TNS_FONT_BUFFER_W, f->CurrentX, fsc->width)){
+        f->CurrentY += f->height+1;
+        f->CurrentX = 0;
+    }
+    fsc->bufferx = f->CurrentX;
+    fsc->buffery = f->CurrentY;
+    f->CurrentX += fsc->width;
+}
+
+tnsFontSingleCharacter *tfntFetchVectorGraphTextureIDW(uint32_t ID){
+    //GLuint revel = 0;
+    //tnsFont *f = FM->VectorsGrapghs;
+    //tnsFontSingleCharacter *fsc = 0;
+    //FT_Glyph glyph = 0;
+    //FT_BitmapGlyph bitmap_glyph;
+    //FT_Bitmap bm;
+    //FT_Face face;
+    //int w, h, i, j;
+    //GLubyte *buf = 0;
+    //int a;
+    //int Size = ((int)(_ICON_SYMBOL_SIZE[ID - 0)) << 6;
+    //int ret;
+
+    //if (!f)
+    //    return 0;
+
+    //if (revel = f->icons[ID].Generated)
+    //    return &f->icons[ID];
+
+    //FT_Set_Char_Size(f->ftface, Size, Size, 96, 96);
+
+    //if (ret = FT_Load_Char(f->ftface, ID, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP))
+    //    return 0;
+
+    //fsc = &f->icons[ID];
+
+    //face = f->ftface;
+
+    //if (FT_Get_Glyph(face->glyph, &glyph))
+    //    return 0;
+
+    //FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+
+    //FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+    //bitmap_glyph = glyph;
+    //bm = bitmap_glyph->bitmap;
+
+    //w = bm.width;
+    //h = bm.rows;
+    //fsc->width = w;
+    //fsc->height = h;
+    //fsc->advx = face->glyph->advance.x / 64.0f;
+    //fsc->advy = face->size->metrics.y_ppem;
+    //fsc->deltax = bitmap_glyph->left;
+    //fsc->deltay = bitmap_glyph->top - h;
+
+    ////tfntApplyCharacterBufferOffset(f, fsc);
+
+    ////glBindTexture(GL_TEXTURE_2D, f->TexBuffer.GLTexHandle);
+
+    //buf = CreateNewBuffer(GLubyte, w * h);
+
+    //for (j = 0; j < h; j++)
+    //{
+    //    for (i = 0; i < w; i++)
+    //    {
+    //        char _vl = bm.buffer[i + w * j];
+    //        buf[i + (h - j - 1) * w] = _vl;
+    //    }
+    //}
+
+    //glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+    //fsc->Tex = tnsCreate2DTexture(GL_ALPHA, w, h, buf);
+
+    //glBindTexture(GL_TEXTURE_2D, 0);
+
+    ////glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, buf);
+    //glBindTexture(GL_TEXTURE_2D, 0);
+
+    //FreeMem(buf);
+
+    //fsc->Generated = 1;
+    //return fsc;
+}
+tnsFontSingleCharacter *tfntFetchCharTextureIDW(uint32_t ch, int UseMono){
+    GLuint revel = 0;
+    tnsFont *f = FM->UsingFont;
+    tnsFontSingleCharacter **use_fsc=UseMono?f->monocharacters:f->characters, *fsc = 0;
+    FT_Glyph glyph = 0;
+    FT_BitmapGlyph bitmap_glyph;
+    FT_Bitmap bm;
+    FT_Face face;
+    int w, h, i, j;
+    GLubyte *buf = 0;
+
+    if (!f) return 0;
+
+    if(ch>TNS_MONO_COUNT){ UseMono=0; use_fsc=f->characters; }
+    if(ch>TNS_UNICODE_COUNT){ return 0; }
+
+    fsc = use_fsc[ch];
+    if(!fsc){ fsc=use_fsc[ch]=calloc(1,sizeof(tnsFontSingleCharacter)); }
+
+    if (revel = fsc->Generated) return fsc;
+
+    if(UseMono && f->ftfacemono){
+        face = f->ftfacemono;
+        if(!FT_Get_Char_Index(face,ch)){return 0;}
+        if (FT_Load_Char(face, ch, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)){ return 0; }
+        if (FT_Get_Glyph(face->glyph, &glyph)){ return 0; }
+    }else{
+        for(int i=0;i<f->NumFaces;i++){
+            if(!f->ftface[i]){continue;}
+            face = f->ftface[i];
+            if(!FT_Get_Char_Index(face,ch)){continue;}
+            if (FT_Load_Char(face, ch, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP)){ continue; }
+            if (FT_Get_Glyph(face->glyph, &glyph)){ continue; }
+            break;
+        }
+        if(!glyph){ return 0; }
+    }
+
+    FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
+
+    FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
+    bitmap_glyph = glyph;
+    bm = bitmap_glyph->bitmap;
+
+    w = bm.width;
+    h = bm.rows;
+    fsc->width = w;
+    fsc->height = h;
+    fsc->advx = face->glyph->advance.x / 64.0f;
+    fsc->advy = face->size->metrics.y_ppem;
+    fsc->deltax = bitmap_glyph->left;
+    fsc->deltay = bitmap_glyph->top - h;
+
+    tfntApplyCharacterBufferOffset(f, fsc);
+
+    tnsBindTexture(&f->TexBuffer);
+    //glBindTexture(GL_TEXTURE_2D, f->TexBuffer.GLTexHandle);
+
+    buf = CreateNewBuffer(GLubyte, w * h);
+
+    for (j = 0; j < h; j++){
+        for (i = 0; i < w; i++){
+            char _vl = bm.buffer[i + w * j];
+            buf[i + (h - j - 1) * w] = _vl;
+        }
+    }
+
+    //glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
+    //glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glTexSubImage2D(GL_TEXTURE_2D, 0, fsc->bufferx, fsc->buffery, w, h, GL_RED, GL_UNSIGNED_BYTE, buf);
+
+    FreeMem(buf);
+
+    fsc->Generated = 1;
+    return fsc;
+}
+tnsFontSingleCharacter *tfntFetchCharacterW(uint32_t ch, int UseMono){
+    tnsFontSingleCharacter* fsc = tfntFetchCharTextureIDW(ch, UseMono);
+    if(fsc) return fsc;
+    return tfntFetchCharTextureIDW('?', UseMono);
+}
+
+int CMP_NAME_IsThisFont(tnsFont *enumed, char *name){
+    return (!strcmp(enumed->fontName, name));
+};
+
+int tnsUseFont(char *name){
+    tnsFont *f;
+    if(!name){f = FM->Fonts.pFirst;}else{ f = lstFindItem(name, CMP_NAME_IsThisFont, &FM->Fonts); }
+
+    if (!f) return 0;
+
+    FM->UsingFont = f;
+
+    return 1;
+};
+
+int tnsStringGetDimension(char* content, uint32_t* contentU, int Count, int WLimit, int* Rows, int UseMono){
+    int sx = 0, sy = FM->UsingFont->height, MA=FM->UsingFont->MonoAdvance;
+    int i, rows=1, advance=1;
+    int C = 0;
+    int len = contentU?strlenU(contentU):(content?strlen(content):0);
+    char hb;
+    int RestoreI;
+    int MaxSX=0;
+
+    if(!WLimit){WLimit=INT_MAX;}
+
+    int UC=1;
+    for (i = 0; i < len && UC; i+=advance){
+        UC = contentU?contentU[i]:laToUnicode(&content[i], &advance);
+        tnsFontSingleCharacter *fsc;
+        if (UC == L'\n'){
+            if(sx>MaxSX) MaxSX=sx;
+            sx = 0; sy += LA_RH; rows++;
+            continue;
+        }else{
+            fsc = tfntFetchCharacterW(UC, UseMono);
+            int dx=fsc->advx; if(UseMono){ dx/=MA; if(dx<1) dx=1; if(dx>1)dx=2; dx*=MA; }
+            if(sx+dx > WLimit){ sx = 0; sy += LA_RH; rows++; }
+            sx += dx;
+            C += 1;
+            if (Count && C == Count) break;
+        }
+    }
+    if(sx==0 && rows>1){rows--;}
+    if(sx>MaxSX) MaxSX=sx;
+    if(Rows) (*Rows)=rows;
+    return MaxSX;
+}
+int tnsStringGetWidth(char *content, int Count, int UseMono){
+    return tnsStringGetDimension(content, 0, Count, 0, 0, UseMono);
+}
+int tnsStringGetWidthU(uint32_t *contentU, int Count, int UseMono){
+    return tnsStringGetDimension(0, contentU, Count, 0, 0, UseMono);
+}
+void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags){
+    int sx = L, sy = (LA_RH!=LA_RH0)?(((((real)FM->UsingFont->height/LA_RH0-0.5)/MAIN.UiScale)+0.5)*LA_RH + T):(FM->UsingFont->height+T);
+    int MA=FM->UsingFont->MonoAdvance;
+    int i,advance=1;
+    int len = contentU?strlenU(contentU):strlen(content);
+    real xo, yo, xl, yl;
+    real TexCoord[12];
+    real VertArr[12];
+    int total_width = 0;
+    tnsFont *f = FM->UsingFont;
+    int FscHeight, RestoreI;
+    int RevY=(Flags&LA_TEXT_REVERT_Y);
+    int UseMono=(Flags&LA_TEXT_MONO);
+
+    int any=0, UC=1; int BreakNow=0;
+    for (i = 0; i < len && UC; i+=advance){
+        UC = contentU?contentU[i]:laToUnicode(&content[i], &advance);
+        tnsFontSingleCharacter *fsc;
+        int cx, cy;
+
+        if (UC == L'\n'){ sx = L; sy += LA_RH; continue; }
+
+        fsc = tfntFetchCharacterW(UC, Flags&LA_TEXT_MONO);
+
+        int dx=fsc->advx; if(UseMono){ dx/=MA; if(dx<1) dx=1; if(dx>1)dx=2; dx*=MA; }
+        if (sx + dx > R){
+            if(Flags&LA_TEXT_LINE_WRAP){
+                sx=L; sy+=LA_RH;
+            }else{
+                if(Flags&LA_TEXT_OVERFLOW_ARROW){ fsc = tfntFetchCharacterW(L'▷', 0); sx=R-fsc->advx; BreakNow=1; }
+                else break;
+            }
+        }
+
+        cx = sx + fsc->deltax;
+        cy = sy - fsc->deltay;
+        xo = (real)fsc->bufferx / (real)TNS_FONT_BUFFER_W;
+        yo = (real)fsc->buffery / (real)TNS_FONT_BUFFER_H;
+        xl = (real)(fsc->bufferx + fsc->width) / (real)TNS_FONT_BUFFER_W;
+        yl = (real)(fsc->buffery + fsc->height) / (real)TNS_FONT_BUFFER_H;
+
+        tnsMakeQuadT2d(TexCoord, xo, yl, xo, yo, xl, yl, xl, yo);
+        if (RevY) tnsMakeQuadT2d(VertArr,
+                          cx, 2 * T - cy + fsc->height,
+                          cx, 2 * T - cy,
+                          cx + fsc->width, 2 * T - cy + fsc->height,
+                          cx + fsc->width, 2 * T - cy);
+        else tnsMakeQuadT2d(VertArr,
+                          cx, +cy - fsc->height,
+                          cx, +cy,
+                          cx + fsc->width, +cy - fsc->height,
+                          cx + fsc->width, +cy);
+
+        tnsUseMaskTexture(&f->TexBuffer);
+        tnsColor4dv(Color);
+        tnsVertexArray2d(VertArr, 6);
+        tnsTexCoordArray2d(TexCoord, 6);
+        any=1;
+
+        sx += dx;
+        
+        if(BreakNow){ break; }
+    }
+    if(any) tnsPackAs(GL_TRIANGLES);
+}
+void tnsDrawStringAutoM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags){
+    int LL;
+    int al = Flags&LA_TEXT_ALIGN;
+    
+    if (!content && !contentU) return;
+    switch (al){
+    case LA_TEXT_ALIGN_AUTO:
+    case LA_TEXT_ALIGN_CENTER: LL = L+(R-L-tnsStringGetDimension(content, contentU, 0, 0, 0, Flags&LA_TEXT_MONO)) / 2; if(LL<L) LL=L; break;
+    default:
+    case LA_TEXT_ALIGN_LEFT: LL = L; break;
+    case LA_TEXT_ALIGN_RIGHT: LL = R-(tnsStringGetDimension(content, contentU, 0, 0, 0, Flags&LA_TEXT_MONO)); break;
+    }
+    tnsDrawStringM(content, contentU, Color, LL, R, T, Flags);
+}
+void tnsDrawStringAuto(char *content, real Color[4], int L, int R, int T, int Flags){
+    tnsDrawStringAutoM(content,0,Color,L,R,T,Flags);
+}
+void tnsDrawStringWithPriority(char *Label, char *MajorContent, real Color[4], int TextAlign, int L, int R, int T, int Flags){
+    int W = R - L;
+    int Str1W = tnsStringGetWidth(Label, 0, Flags&LA_TEXT_MONO);
+    int Str2W = tnsStringGetWidth(MajorContent, 0, Flags&LA_TEXT_MONO);
+    if (Str1W + Str2W > W){
+        if (Str2W < W){
+            tnsDrawStringM(MajorContent, 0, Color, R - Str2W, R, T, Flags);
+            tnsDrawStringM(Label, 0, Color, L, R - Str2W, T, Flags);
+        }else
+            tnsDrawStringM(MajorContent, 0, Color, L, R, T, Flags);
+    }else{
+        int LL = L, ML;
+        switch (TextAlign){
+        case LA_TEXT_ALIGN_CENTER:
+            ML = L + Str1W + (W - (Str1W + Str2W)) / 2;
+            break;
+        case LA_TEXT_ALIGN_LEFT:
+            ML = L + Str1W;
+            break;
+        default:
+        case LA_TEXT_ALIGN_AUTO:
+        case LA_TEXT_ALIGN_RIGHT:
+            ML = R - Str2W;
+            break;
+        }
+
+        tnsDrawStringM(Label, 0, Color, LL, R, T, Flags);
+        tnsDrawStringM(MajorContent, 0, Color, ML, R, T, Flags);
+    }
+}
+void tnsDrawIcon(uint32_t ID, real Color[4], int L,int R, int T, int Flags){
+    char buf[5]={0}; char* next; laToUTF8(ID,buf,&next);
+    tnsDrawStringAuto(buf, Color, L,R,T,Flags);
+}
+
+//=====================================================================================[Object]
+
+tnsObject *tnsFindObject(char *Name, tnsObject *FromObj){
+    tnsObject *io; tnsObject *ro;
+    laListHandle* l=FromObj?(&FromObj->ChildObjects):(&T->World.AllObjects);
+    for (laListItemPointer*lip=l->pFirst;lip;lip=lip->pNext){
+        io=((l==&T->World.AllObjects)?lip:lip->p); if (strSame(io->Name->Ptr, Name)){ return io; }
+        if (ro = tnsFindObject(Name, io)) return ro;
+    }
+    return 0;
+}
+
+void tnsExtractSelfTransformValue(tnsObject *o){
+    if (!o) return;
+    tnsExtractLocation44d(o->SelfTransform, &o->Location[0], &o->Location[1], &o->Location[2]);
+    tnsExtractXYZEuler44d(o->SelfTransform, &o->Rotation[0], &o->Rotation[1], &o->Rotation[2]);
+    tnsExtractUniformScale44d(o->SelfTransform, &o->Scale);
+}
+void tnsExtractGlobalTransformValue(tnsObject *o){
+    if (!o) return;
+    tnsExtractLocation44d(o->GlobalTransform, &o->GLocation[0], &o->GLocation[1], &o->GLocation[2]);
+    tnsExtractXYZEuler44d(o->GlobalTransform, &o->GRotation[0], &o->GRotation[1], &o->GRotation[2]);
+    tnsExtractUniformScale44d(o->GlobalTransform, &o->GScale);
+}
+void tnsCopyGlobalTransform(tnsObject *to, tnsObject *from){
+    memcpy(to->GlobalTransform, from->GlobalTransform, sizeof(tnsMatrix44d));
+    memcpy(to->GLocation, from->GLocation, sizeof(tnsVector3d));
+    memcpy(to->GRotation, from->GRotation, sizeof(tnsVector3d));
+    to->GScale = from->GScale;
+    tnsGlobalTransformValueChanged(to);
+}
+
+void tnsSelfMatrixChanged(tnsObject* o, int ApplyToChild){
+    if (!o->ParentObject){ memcpy(o->GlobalTransform, o->SelfTransform, sizeof(tnsMatrix44d)); }
+    else{ tnsMultiply44d(o->GlobalTransform, o->ParentObject->GlobalTransform, o->SelfTransform); }
+    tnsExtractSelfTransformValue(o);
+    tnsExtractGlobalTransformValue(o);
+    if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); }
+}
+void tnsGlobalMatrixChanged(tnsObject* o, int ApplyToChild){
+    if (!o->ParentObject){ memcpy(o->SelfTransform, o->GlobalTransform, sizeof(tnsMatrix44d)); }
+    else{ tnsMatrix44d inv;
+        tnsInverse44d(inv, o->ParentObject->GlobalTransform);
+        tnsMultiply44d(o->SelfTransform, inv, o->GlobalTransform); }
+    tnsExtractSelfTransformValue(o);
+    tnsExtractGlobalTransformValue(o);
+    if(ApplyToChild) for (laListItemPointer* li=o->ChildObjects.pFirst;li;li=li->pNext){ tnsSelfMatrixChanged(li->p,1); }
+}
+void tnsSelfTransformValueChanged(tnsObject* o){
+    tnsMatrix44d Trans, Rot1, Rot2, Rot3, Scale, Res1, Res2;
+    tnsLoadIdentity44d(o->SelfTransform);
+    tnsMakeTranslationMatrix44d(Trans, LA_COLOR3(o->Location));
+    tnsMakeScaleMatrix44d(Scale, o->Scale,o->Scale,o->Scale);
+
+    tnsMakeRotationXMatrix44d(Rot1, o->Rotation[0]);
+    tnsMakeRotationYMatrix44d(Rot2, o->Rotation[1]);
+    tnsMakeRotationZMatrix44d(Rot3, o->Rotation[2]);
+    switch (o->RotationMode){
+    case TNS_ROTATION_ZYX_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot3); break;
+    case TNS_ROTATION_XZY_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot2); break;
+    case TNS_ROTATION_YXZ_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot3); break;
+    case TNS_ROTATION_YZX_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot1); break;
+    case TNS_ROTATION_ZXY_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot2); break;
+    case TNS_ROTATION_XYZ_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot1); break;
+    }
+    tnsMultiply44d(o->SelfTransform, Res1, Scale);
+    tnsSelfMatrixChanged(o,1);
+}
+void tnsGlobalTransformValueChanged(tnsObject* o){
+    tnsMatrix44d Trans, Rot1, Rot2, Rot3, Scale, Res1, Res2;
+    tnsLoadIdentity44d(o->GlobalTransform);
+    tnsMakeTranslationMatrix44d(Trans, LA_COLOR3(o->GLocation));
+    tnsMakeScaleMatrix44d(Scale, o->GScale,o->GScale,o->GScale);
+
+    tnsMakeRotationXMatrix44d(Rot1, o->GRotation[0]);
+    tnsMakeRotationYMatrix44d(Rot2, o->GRotation[1]);
+    tnsMakeRotationZMatrix44d(Rot3, o->GRotation[2]);
+    switch (o->RotationMode){
+    case TNS_ROTATION_ZYX_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot3); break;
+    case TNS_ROTATION_XZY_EULER: tnsMultiply44d(Res1, Trans, Rot1); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot2); break;
+    case TNS_ROTATION_YXZ_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot3); break;
+    case TNS_ROTATION_YZX_EULER: tnsMultiply44d(Res1, Trans, Rot2); tnsMultiply44d(Res2, Res1, Rot3); tnsMultiply44d(Res1, Res2, Rot1); break;
+    case TNS_ROTATION_ZXY_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot1); tnsMultiply44d(Res1, Res2, Rot2); break;
+    case TNS_ROTATION_XYZ_EULER: tnsMultiply44d(Res1, Trans, Rot3); tnsMultiply44d(Res2, Res1, Rot2); tnsMultiply44d(Res1, Res2, Rot1); break;
+    }
+    tnsMultiply44d(o->GlobalTransform, Res1, Scale);
+    tnsGlobalMatrixChanged(o,1);
+}
+
+void tnsSetCurrentRoot(tnsObject *o){
+    if(o->Type!=TNS_OBJECT_ROOT) return;
+    T->World.ActiveRoot=o;
+    // memAssignRef(s, &s->CurrentObject, o); we can't use this apparently because World is not hyper 2.
+    // XXX: Needs fake mempool/user, or T->World prop redesign because T is runtime allocated.
+}
+void tnsInitObjectBase(tnsObject *o, tnsObject *under, char *Name, int Type,
+                        real AtX, real AtY, real AtZ,
+                        real RotX, real RotY, real RotZ, real RotW, u8bit RotationMode,
+                        real Scale){
+    if (!o) return;
+    strSafeSet(&o->Name, Name);
+    o->Type = Type;
+    o->Location[0] = AtX;
+    o->Location[1] = AtY;
+    o->Location[2] = AtZ;
+    o->Rotation[0] = RotX;
+    o->Rotation[1] = RotY;
+    o->Rotation[2] = RotZ;
+    o->Rotation[3] = RotW;
+    o->RotationMode = RotationMode;
+    o->Scale = Scale;
+    o->Show = 1;
+    o->DrawMode = GL_LINE_LOOP;
+    tnsSelfTransformValueChanged(o);
+    lstAppendItem(&T->World.AllObjects, o);
+    if (under){ lstAppendPointer(&under->ChildObjects, o);
+        tnsObject* root=under->Type==TNS_OBJECT_ROOT?under:under->InRoot; memAssignRef(o, &o->InRoot, root); 
+    }
+}
+int tnsCheckParentable(tnsObject* child, tnsObject* parent){
+    if(child==parent||parent->ParentObject==child)return 0; tnsObject* o=parent; while(o=o->ParentObject){ if(o==parent) return 0; } return 1;
+}
+void tnsParentObject(tnsObject *child, tnsObject *parent, int KeepTransform){
+    if (!child || !parent || child->ParentObject==parent || parent->ParentObject==child || parent==child) return;
+
+    if (child->ParentObject) lstRemovePointer(&child->ParentObject->ChildObjects, child);
+    else lstRemovePointer(&child->InRoot->ChildObjects, child);
+
+    lstAppendPointer(&parent->ChildObjects, child);
+    memAssignRef(child, &child->ParentObject, parent);
+
+    if(KeepTransform) tnsGlobalMatrixChanged(child, 1);
+    else tnsSelfMatrixChanged(child, 1);
+}
+void tnsUnparentObject(tnsObject *o, int KeepTransform){
+    if (!o || !o->ParentObject) return;
+    lstRemovePointer(&o->ParentObject->ChildObjects, o);
+    lstAppendPointer(&o->InRoot->ChildObjects, o);
+    memAssignRef(o, &o->ParentObject, 0);
+
+    if(KeepTransform) tnsGlobalMatrixChanged(o,1);
+    else tnsSelfMatrixChanged(o,1);
+}
+void tnsRotateObjectLocalValues(tnsObject *o, real x, real y, real z){
+    o->Rotation[0] += x; o->Rotation[1] += y; o->Rotation[2] += z;
+    tnsSelfTransformValueChanged(o);
+}
+void tnsMoveObjectLocal(tnsObject *o, real x, real y, real z){
+    tnsMatrix44d mat, res1, res2, res3;
+    tnsMakeTranslationMatrix44d(res2, x, y, z);
+    tnsMultiply44d(res1, o->SelfTransform, res2);
+    memcpy(o->SelfTransform, res1, sizeof(tnsMatrix44d));
+    tnsSelfMatrixChanged(o,1);
+}
+void tnsMoveObjectGlobal(tnsObject *o, real x, real y, real z){
+    tnsMatrix44d mat, res1, res2, res3;
+    tnsMakeTranslationMatrix44d(res2, x, y, z);
+    tnsMultiply44d(res1, res2, o->GlobalTransform); //if reverse then local
+    memcpy(o->GlobalTransform, res1, sizeof(tnsMatrix44d));
+    tnsGlobalMatrixChanged(o,1);
+}
+void tnsRotateObjectGlobal(tnsObject *o, real x, real y, real z, real angle, real cx,real cy,real cz){
+    tnsMatrix44d tback,tfwd,rot,rot2,res1,res2;
+    real xs, ys, zs;
+    tnsMakeRotationMatrix44d(rot,angle,x,y,z);
+    tnsMakeRotationMatrix44d(rot2,-angle,x,y,z);//why?
+
+    tnsMakeTranslationMatrix44d(tfwd, o->GLocation[0],o->GLocation[1],o->GLocation[2]);
+    tnsInverse44d(tback,tfwd);
+    tnsMultiply44d(res1,o->GlobalTransform,tback);
+    tnsMultiply44d(res2,rot,res1);
+    tnsMultiply44d(o->GlobalTransform,res2,tfwd);
+
+    tnsVector3d delta; delta[0]=o->GLocation[0]-cx; delta[1]=o->GLocation[1]-cy; delta[2]=o->GLocation[2]-cz;
+    tnsVector3d c; c[0]=cx; c[1]=cy; c[2]=cz; tnsVector3d r;
+    tnsApplyRotation43d(r,rot2,delta);
+    tnsVectorPlus3d(&o->GlobalTransform[12],c,r);
+    //memcpy(o->GlobalTransform, res1, sizeof(tnsMatrix44d));
+    tnsGlobalMatrixChanged(o,1);
+}
+void tnsRotateObjectLocal(tnsObject *o, real x, real y, real z, real angle, real gcx,real gcy,real gcz){
+    tnsMatrix44d tback,tfwd,rot,res1,res2;
+    real xs, ys, zs;
+    tnsVector3d gp,gpt; gp[0]=gcx; gp[1]=gcy; gp[2]=gcz;
+    tnsApplyTransform43d(gpt,o->GlobalTransform,gp);
+    tnsMakeTranslationMatrix44d(tfwd, gpt[0]-gcx, gpt[0]-gcy, gpt[0]-gcz);
+    tnsInverse44d(tback,tfwd);
+    tnsMakeRotationMatrix44d(rot,angle,x,y,z);
+    tnsMultiply44d(res1,o->SelfTransform,tback);
+    tnsMultiply44d(res2,res1,rot);
+    tnsMultiply44d(o->SelfTransform,res2,tfwd);
+    tnsSelfMatrixChanged(o,1);
+}
+void tnsScaleObject(tnsObject *o, real fac, real cx,real cy,real cz){
+    tnsMatrix44d sca,res1,res2;
+    tnsMakeScaleMatrix44d(sca,fac,fac,fac);
+    tnsMultiply44d(res1,o->GlobalTransform,sca);
+    tnsVector3d delta; delta[0]=res1[12]-cx; delta[1]=res1[13]-cy; delta[2]=res1[14]-cz;
+    tnsVector3d c; c[0]=cx; c[1]=cy; c[2]=cz;
+    tnsVectorMultiSelf3d(delta, fac);
+    tnsVectorPlus3d(&res1[12],c,delta);
+    memcpy(o->GlobalTransform, res1, sizeof(tnsMatrix44d));
+    tnsGlobalMatrixChanged(o,1);
+}
+void tnsZoomViewingCamera(tnsCamera *c, real Ratio){
+    if (c->FocusDistance < 0.1) return;
+    tnsMoveObjectLocal(c, 0, 0, -c->FocusDistance * Ratio);
+    c->FocusDistance *= (1 - Ratio);
+}
+void tnsRotateViewingCamera(tnsCamera *c, real x, real z){
+    tnsMoveObjectLocal(c, 0, 0, -c->FocusDistance);
+    tnsRotateObjectLocalValues(c, x, 0, z);
+    tnsMoveObjectLocal(c, 0, 0, c->FocusDistance);
+}
+void tnsGetCameraMovingDeltas(tnsCamera *c, int ViewportW, int ViewportH, real x, real y, tnsVector4d p){
+    memset(p, 0, sizeof(tnsVector4d));
+    tnsVector4d tp = {0};
+    tnsMatrix44d combine, projection, projinv, vpinv, vp;
+
+    tnsLoadIdentity44d(projection);
+    tnsMakePerspectiveMatrix44d(projection, c->FOV, (real)ViewportW / (real)ViewportH, c->ZMin, c->ZMax);
+    tnsMakeViewportMatrix44d(vp, ViewportW, ViewportH, c->ZMax, c->ZMin);
+    tnsInverse44d(projinv, projection);
+    tnsInverse44d(vpinv, vp);
+
+    p[2] = -c->FocusDistance;
+    p[3] = 1;
+    tnsApplyTransform44d(tp, projection, p);
+    tnsVectorMultiSelf3d(tp, 1 / tp[3]);
+    tnsApplyTransform43d(p, vp, tp);
+    p[0] += x;
+    p[1] += y;
+
+    tnsApplyTransform43d(tp, vpinv, p);
+    tnsVectorMultiSelf3d(tp, tp[3]);
+    tnsApplyTransform44d(p, projinv, tp);
+}
+void tnsTranslateViewingCamera(tnsCamera *c, int ViewportW, int ViewportH, real x, real y){
+    tnsVector4d p={0};
+    tnsGetCameraMovingDeltas(c,ViewportW, ViewportH, x,y,p);
+    tnsMoveObjectLocal(c, p[0], p[1], 0);
+}
+
+tnsObject *tnsCreateRootObject(char *name){
+    tnsWorld *w = &T->World;
+    tnsObject *o = memAcquireHyper(sizeof(tnsObject));
+
+    o->Type==TNS_OBJECT_ROOT;
+    strSafeSet(&o->Name, name);
+    lstAppendItem(&w->RootObjects, o);
+
+    w->ActiveRoot = o; // XXX: same here
+
+    return o;
+}
+void tnsDestroyRootObject(tnsObject *root){
+    tnsWorld *w = &T->World;
+    tnsObject *o, *NextO;
+    w->ActiveRoot = root->Item.pPrev ? root->Item.pPrev : root->Item.pNext ? root->Item.pNext : 0;
+
+    lstRemoveItem(&w->RootObjects, root);
+    while (lstPopPointer(&root->ChildObjects));
+    strSafeDestroy(&root->Name);
+    memFree(root);
+}
+void tnsDestroyObject(tnsObject *o){
+    if(o->Type==TNS_OBJECT_ROOT){ tnsDestroyRootObject(o); return; }
+
+    tnsUnparentObject(o,1);
+    while(o->ChildObjects.pFirst){ tnsUnparentObject(((laListItemPointer*)o->ChildObjects.pFirst)->p, 1); }
+
+    lstRemoveItem(&T->World.AllObjects, o);
+
+    if(o->Type==TNS_OBJECT_MESH){ tnsInvaliateMeshBatch(o); }
+
+    strSafeDestroy(&o->Name);
+    memFree(o);
+}
+tnsCamera *tnsCreateCamera(tnsObject *under, char *Name, real FOV,
+                        real AtX, real AtY, real AtZ,
+                        real RotX, real RotY, real RotZ,
+                        real FocusDistance){
+    tnsCamera *c; tnsWorld *w = &T->World;
+
+    c = memAcquireHyper(sizeof(tnsCamera));
+    tnsInitObjectBase(&c->Base, under, Name, TNS_OBJECT_CAMERA, AtX, AtY, AtZ, RotX, RotY, RotZ, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
+    c->FOV = FOV;
+    c->CameraType = TNS_PRESPECTIVE_CAMERA;
+    c->ZMin = 0.1f;
+    c->ZMax = 1000.0f;
+    c->FocusDistance = FocusDistance;
+    c->OrthScale = 1.0f;
+
+    return c;
+}
+tnsObject *tnsCreateEmpty(tnsObject *under, char *Name, real AtX, real AtY, real AtZ){
+    tnsObject *o; tnsWorld *w = &T->World; if (!under) return 0;
+
+    o = memAcquireHyper(sizeof(tnsObject));
+    tnsInitObjectBase(o, under, Name, TNS_OBJECT_EMPTY, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
+
+    return o;
+}
+tnsLight *tnsCreateLight(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real Strength, int UniDirectional){
+    tnsLight *l; tnsWorld *w = &T->World; if (!under) return 0;
+    tnsObject* root=under->Type==TNS_OBJECT_ROOT?under:under->InRoot;
+    if (UniDirectional&&under){
+        if(root){ if(root->ParentObject) return root->ParentObject; }
+    }
+
+    l = memAcquireHyper(sizeof(tnsLight));
+    tnsInitObjectBase(&l->Base, under, Name, TNS_OBJECT_LIGHT, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
+    l->Strength = Strength;
+    l->UniDirectional = UniDirectional;
+
+    if (root && UniDirectional && !root->ParentObject) memAssignRef(root, &root->ParentObject,l);
+    return l;
+}
+
+int tnsAnyObjectsSelected(tnsObject *root){
+    for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; if(o->Flags&TNS_OBJECT_FLAGS_SELECTED) return 1; 
+        if(o->ChildObjects.pFirst && tnsAnyObjectsSelected(o)) return 1;
+    } return 0;
+}
+void tnsDeselectAllObjects(tnsObject *root){
+    for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; o->Flags&=(~TNS_OBJECT_FLAGS_SELECTED);
+        if(o->ChildObjects.pFirst)tnsDeselectAllObjects(o);
+    }
+}
+void tnsSelectAllObjects(tnsObject *root){
+    for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ tnsObject* o=lip->p; o->Flags|=TNS_OBJECT_FLAGS_SELECTED;
+        if(o->ChildObjects.pFirst)tnsSelectAllObjects(o);
+    }
+}
+void tnsSelectObject(tnsObject* o, int Select, int Toggle){
+    if(!o) return;
+    if(Toggle) tnsSelectObject(o,(o->Flags&TNS_OBJECT_FLAGS_SELECTED?0:1),0);
+    elif(Select) o->Flags|=TNS_OBJECT_FLAGS_SELECTED; else o->Flags&=(~TNS_OBJECT_FLAGS_SELECTED);
+}
+
+void tnsGetCameraViewProjection(tnsMatrix44d* mat, int w, int h, tnsCamera* Camera){
+    tnsMatrix44d inv, result;
+    tnsMakePerspectiveMatrix44d(mat, Camera->FOV, (real)w / (real)h, Camera->ZMin, Camera->ZMax);
+    tnsInverse44d(inv, Camera->Base.GlobalTransform);
+    tnsMultiply44d(result, mat, inv);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+}
+void tnsApplyCameraView(int W, int H, tnsCamera *Camera){
+    tnsMatrixStackItem *tmsi = tKnlGetCurrentMatStackItem();
+    tnsShader *current_shader = 0;
+    real *mat;
+    tnsMatrix44d result, inv;
+
+    if (!Camera) return;
+
+    mat = tnsGetProjectionMatrix();
+    tnsMakePerspectiveMatrix44d(mat, Camera->FOV, (real)W / (real)H, Camera->ZMin, Camera->ZMax);
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyProjection(current_shader, mat);
+        tnsShaderApplyProjectionInverse(current_shader, mat);
+    }
+
+    tnsResetViewMatrix();
+    mat = tnsGetViewMatrix();
+    tnsInverse44d(inv, Camera->Base.GlobalTransform);
+    tnsMultiply44d(result, mat, inv);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyView(current_shader, result);
+    }
+}
+void tnsApplyShadowCameraView(tnsLight *Light){
+    tnsMatrixStackItem *tmsi = tKnlGetCurrentMatStackItem();
+    tnsShader *current_shader = 0;
+    tnsMatrix44d mat;
+    tnsMatrix44d result, inv;
+
+    if (!Light || !Light->UniDirectional) return;
+
+    //mat = tnsGetProjectionMatrix();
+    tnsMakeOrthoMatrix44d(mat, -1000,1000,-1000,1000,-1000,1000);
+
+    tnsInverse44d(inv, Light->Base.GlobalTransform);
+    tnsMultiply44d(result, mat, inv);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyShadowMatrix(current_shader,mat);
+    }
+}
+
+void tnsApplyObjectMatrix(tnsObject *Object){
+    tnsShader *current_shader = 0;
+    real *mat;
+    tnsMatrix44d result;
+
+    if (!Object) return;
+
+    mat = tnsGetModelMatrix();
+
+    tnsMultiply44d(result, mat, Object->SelfTransform);
+    memcpy(mat, result, sizeof(tnsMatrix44d));
+
+    //Actually This Works Pretty Fast,but we are currently testing its functionality;
+    //memcpy(mat, Object->GlobalTransform, sizeof(tnsMatrix44d));
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyModel(current_shader, mat);
+    }
+}
+
+void tnsLookAt(tnsObject *o, tnsVector3d Target, tnsVector3d Up){
+    tnsVector4d target = {0};
+    tnsMatrix44d mat, res, res2;
+    real *d;
+    tnsShader *current_shader = 0;
+
+    d = tnsGetModelMatrix();
+
+    tnsMakeZTrackingMatrix44d(mat, o->GLocation, target, Up);
+    tnsLoadIdentity44d(res);
+    tnsMakeTranslationMatrix44d(res,o->GLocation[0],o->GLocation[1],o->GLocation[2]);
+    tnsMultiply44d(res2, res, mat);
+    memcpy(o->SelfTransform, res2, sizeof(tnsMatrix44d));
+
+    tnsSelfMatrixChanged(o,1);
+
+    if (current_shader = tKnlGetActiveShader()){
+        tnsShaderApplyModel(current_shader, d);
+    }
+}
+
+void tnsDrawCamera(tnsObject *o){
+    tnsCamera *c = o;
+    real fov_2 = c->FOV / 2;
+    real ex, ey, ez;
+    ey = 10 * sin(fov_2);
+    ex = ey;
+    ez = 10 * cos(fov_2);
+
+    //if (T->CurrentShader != T->uiShader) tnsEnableShaderv(T->uiShader);
+
+    tnsColor4d(1, 1, 1, 1);
+
+    tnsVertex3d(ex, ey, -ez);
+    tnsVertex3d(ex, -ey, -ez);
+    tnsVertex3d(0.0, 0.0, 0.0);
+    tnsVertex3d(ex, ey, -ez);
+    tnsVertex3d(-ex, ey, -ez);
+    tnsVertex3d(0.0, 0.0, 0.0);
+    tnsVertex3d(-ex, -ey, -ez);
+    tnsVertex3d(-ex, ey, -ez);
+
+    tnsPackAs(GL_LINE_STRIP);
+    tnsFlush();
+}
+void tnsDrawThisObject(tnsObject *o,tnsObject *active, int DrawAsSelection){
+    if (!o->Show) return;
+    switch (o->Type){
+    case TNS_OBJECT_MESH:
+        tnsDrawMeshObject(o, DrawAsSelection, active);
+        break;
+    case TNS_OBJECT_CAMERA:
+        tnsDrawCamera(o);
+        break;
+    case TNS_OBJECT_EMPTY:
+    default:
+        ////if (T->CurrentShader != T->uiShader) tnsEnableShaderv(T->uiShader);
+        //tnsVertex3d(-1.0, 0.0, 0.0);
+        //tnsVertex3d(5.0, 0.0, 0.0);
+        //tnsVertex3d(0.0, 5.0, 0.0);
+        //tnsVertex3d(0.0, -1.0, 0.0);
+        //tnsVertex3d(0.0, 0.0, -1.0);
+        //tnsVertex3d(0.0, 0.0, 5.0);
+        //tnsColor4d(1, 1, 1, 1);
+        //tnsPackAs(GL_LINES);
+        //tnsFlush();
+        break;
+    }
+}
+
+void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsSelection){
+    tnsObject *o; if(!from) return;
+
+    for (laListItemPointer* lip=from->ChildObjects.pFirst;lip;lip=lip->pNext){
+        o=lip->p;
+        tnsPushMatrix(); tnsApplyObjectMatrix(o);
+        tnsDrawThisObject(o, active, DrawAsSelection);
+        if (o->ChildObjects.pFirst){ tnsDrawObjectTree(o, active, DrawAsSelection); }
+        tnsPopMatrix();
+    }
+}
+
+//===================================================================[Material]
+
+tnsMaterial *tnsCreateMaterial(char *Name){
+    tnsMaterial *m; if(!Name || !Name[0]) return 0;
+
+    m = memAcquireHyper(sizeof(tnsMaterial));
+    strSafeSet(&m->Name, Name);
+    lstAppendItem(&T->World.Materials, m);
+    return m;
+}
+tnsMaterial *tnsFindMaterialByIndex(int index){
+    tnsMaterial *m; int i = 0;
+    for (m = T->World.Materials.pFirst; m; m = m->Item.pNext){
+        if (i == index){ m->ID = i; return m; } i++;
+    }
+    return 0;
+}
+tnsMaterial *tnsFindMaterial(char *name){
+    tnsMaterial *m;
+    int i = 0;
+    for (m = T->World.Materials.pFirst; m; m = m->Item.pNext){
+        if (strSame(m->Name->Ptr, name)){ return m; }
+    }
+    return 0;
+}
+
+//==================================================================[Util]
+
+#define MAX3(a, b, c) \
+    a > b ? (a > c ? a : c) : (b > c ? b : c)
+
+#define MIN3(a, b, c) \
+    a < b ? (a < c ? a : c) : (b < c ? b : c)
+
+extern LA MAIN;
+
+void tnsSingleLinearToLog(real *a, real gamma){
+    if (*a < 0) *a = 0;
+    *a = powf(*a, gamma);
+}
+void tnsSingleLogToLinear(real *a, real gamma){
+    if (*a < 0) *a = 0;
+    *a = powf(*a, 1.0f / gamma);
+}
+void tnsLinearToLog(real *rgb, real gamma){
+    if (rgb[0] < 0) rgb[0] = 0;
+    if (rgb[1] < 0) rgb[1] = 0;
+    if (rgb[2] < 0) rgb[2] = 0;
+    rgb[0] = powf(rgb[0], gamma);
+    rgb[1] = powf(rgb[1], gamma);
+    rgb[2] = powf(rgb[2], gamma);
+}
+void tnsLogToLinear(real *rgb, real gamma){
+    if (rgb[0] < 0) rgb[0] = 0;
+    if (rgb[1] < 0) rgb[1] = 0;
+    if (rgb[2] < 0) rgb[2] = 0;
+    rgb[0] = powf(rgb[0], 1.0f / gamma);
+    rgb[1] = powf(rgb[1], 1.0f / gamma);
+    rgb[2] = powf(rgb[2], 1.0f / gamma);
+}
+void tnsRgbToLuminance(real *rgb){
+    real l;
+    if (rgb[0] < 0) rgb[0] = 0;
+    if (rgb[1] < 0) rgb[1] = 0;
+    if (rgb[2] < 0) rgb[2] = 0;
+    l = rgb[0] * 0.299 + rgb[1] * 0.587 + rgb[2] * 0.114;
+    rgb[0] = rgb[1] = rgb[2] = l;
+}
+
+static const double LA_LUMA_WEIGHTS[]={ 0.2126, 0.7152, 0.0722 };
+void tnsHCYtoRGB(real *hcy, real *rgb){
+    double red, green, blue;
+    double Y_peak = 0., H_insec, X, m;
+    int H_sec;
+
+    double hue = hcy[0];
+    double chroma = hcy[1];
+    double luma = hcy[2];
+    double* weights=LA_LUMA_WEIGHTS;
+
+    if (chroma < DBL_EPSILON){
+        red = green = blue = luma;
+    }else{
+        hue = fmod(hue, 1.0);
+        hue += hue < 0.0;
+        hue *= 6.0;
+
+        H_sec = (int)hue;
+
+        switch (H_sec){
+        case 0:
+            H_insec = hue - H_sec;
+            Y_peak = weights[0] + H_insec * weights[1];
+            chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+            X = chroma * H_insec;
+            m = luma - (weights[0] * chroma + weights[1] * X);
+            red = m + chroma;
+            green = m + X;
+            blue = m;
+            break;
+        case 1:
+            H_insec = 1. - (hue - H_sec);
+            Y_peak = weights[1] + H_insec * weights[0];
+            chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+            X = chroma * H_insec;
+            m = luma - (weights[0] * X + weights[1] * chroma);
+            red = m + X;
+            green = m + chroma;
+            blue = m;
+            break;
+        case 2:
+            H_insec = hue - H_sec;
+            Y_peak = weights[1] + H_insec * weights[2];
+            chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+            X = chroma * H_insec;
+            m = luma - (weights[1] * chroma + weights[2] * X);
+            red = m;
+            green = m + chroma;
+            blue = m + X;
+            break;
+        case 3:
+            H_insec = 1. - (hue - H_sec);
+            Y_peak = weights[2] + H_insec * weights[1];
+            chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+            X = chroma * H_insec;
+            m = luma - (weights[1] * X + weights[2] * chroma);
+            red = m;
+            green = m + X;
+            blue = m + chroma;
+            break;
+        case 4:
+            H_insec = hue - H_sec;
+            Y_peak = weights[2] + H_insec * weights[0];
+            chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+            X = chroma * H_insec;
+            m = luma - (weights[0] * X + weights[2] * chroma);
+            red = m + X;
+            green = m;
+            blue = m + chroma;
+            break;
+        default:
+            H_insec = 1. - (hue - H_sec);
+            Y_peak = weights[0] + H_insec * weights[2];
+            chroma *= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+            X = chroma * H_insec;
+            m = luma - (weights[0] * chroma + weights[2] * X);
+            red = m + chroma;
+            green = m;
+            blue = m + X;
+            break;
+        }
+    }
+
+    rgb[0] =red;
+    rgb[1] =green;
+    rgb[2] =blue;
+}
+void tnsRGBtoHCY(real *rgb, real *hcy){
+    double hue, chroma, luma;
+    double X, Y_peak = 0.;
+    int H_sec = 4, t = -1;
+    double* weights=LA_LUMA_WEIGHTS;
+
+    int ix[3] = {0, 1, 2};
+
+    if (rgb[0] < rgb[1]){
+        if (rgb[1] > rgb[2]){
+            if (rgb[0] < rgb[2]){
+                ix[1] = 2;
+                ix[2] = 1;
+                H_sec = 2;
+                t = 1;
+            }else{
+                ix[0] = 2;
+                ix[1] = 0;
+                ix[2] = 1;
+                H_sec = 2;
+            }
+        }
+    }else{
+        if (rgb[1] < rgb[2]){
+            if (rgb[0] < rgb[2]){
+                ix[0] = 1;
+                ix[1] = 0;
+                H_sec = 4;
+                t = 1;
+            }else{
+                ix[0] = 1;
+                ix[1] = 2;
+                ix[2] = 0;
+                H_sec = 6;
+            }
+        }else{
+            ix[0] = 2;
+            ix[2] = 0;
+            H_sec = 0;
+            t = 1;
+        }
+    }
+
+    luma = weights[0] * rgb[0] + weights[1] * rgb[1] + weights[2] * rgb[2];
+    chroma = rgb[ix[2]] - rgb[ix[0]];
+
+    if (chroma >= DBL_EPSILON){
+        X = (rgb[ix[1]] - rgb[ix[0]]) / chroma;
+
+        Y_peak = weights[ix[2]] + X * weights[ix[1]];
+        if (luma != 0. && luma != 1.) chroma /= luma < Y_peak ? luma / Y_peak : (1. - luma) / (1. - Y_peak);
+
+        hue = (H_sec + t * X) / 6.;
+    }else
+        chroma = hue = 0.0;
+
+    hcy[0] = hue;
+    hcy[1] = chroma;
+    hcy[2] = luma;
+}
+
+void tnsClearAll(){
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+void tnsClearColorv(real *rgba){
+    glClearColor(rgba[0], rgba[1], rgba[2], rgba[3]);
+}
+void tnsClearColor(real r, real g, real b, real a){
+    glClearColor(r, g, b, a);
+}
+
+//Assuming *result is long enough
+void tnsMakeIndexUInt(unsigned int *result, int num, ...){
+    int i;
+    va_list list;
+
+    va_start(list, num);
+
+    for (i = 0; i < num; i++){
+        result[i] = va_arg(list, unsigned int);
+    }
+
+    va_end(list);
+}
+void tnsMakeTriangle(real *arr, real x1, real y1, real x2, real y2, real x3, real y3){
+    arr[0] = x1;
+    arr[1] = y1;
+    arr[2] = x2;
+    arr[3] = y2;
+    arr[4] = x3;
+    arr[5] = y3;
+}
+void tnsMakeQuad2d(real *arr, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4){
+    arr[0] = x1;
+    arr[1] = y1;
+    arr[2] = x2;
+    arr[3] = y2;
+    arr[4] = x3;
+    arr[5] = y3;
+    arr[6] = x4;
+    arr[7] = y4;
+}
+void tnsMakeQuadT2d(real *arr, real x1, real y1, real x2, real y2, real x3, real y3, real x4, real y4){
+    arr[0] = x1;
+    arr[1] = y1;
+    arr[2] = x2;
+    arr[3] = y2;
+
+    arr[4] = x3;
+    arr[5] = y3;
+    arr[6] = x2;
+    arr[7] = y2;
+    
+    arr[8] = x3;
+    arr[9] = y3;
+    arr[10] = x4;
+    arr[11] = y4;
+}
+void tnsMakeQuad3d(real *arr, real x1, real y1, real z1, real x2, real y2, real z2, real x3, real y3, real z3, real x4, real y4, real z4){
+    arr[0] = x1;
+    arr[1] = y1;
+    arr[2] = z1;
+    arr[3] = x2;
+    arr[4] = y2;
+    arr[5] = z2;
+    arr[6] = x3;
+    arr[7] = y3;
+    arr[8] = z3;
+    arr[9] = x4;
+    arr[10] = y4;
+    arr[11] = z4;
+}
+void tnsMakeQuad4d(real *arr, real x1, real y1, real z1, real w1, real x2, real y2, real z2, real w2, real x3, real y3, real z3, real w3, real x4, real y4, real z4, real w4){
+    arr[0] = x1;
+    arr[1] = y1;
+    arr[2] = z1;
+    arr[3] = w1;
+    arr[4] = x2;
+    arr[5] = y2;
+    arr[6] = z2;
+    arr[7] = w2;
+    arr[8] = x3;
+    arr[9] = y3;
+    arr[10] = z3;
+    arr[11] = w3;
+    arr[12] = x4;
+    arr[13] = y4;
+    arr[14] = z4;
+    arr[15] = w4;
+}
+void tnsMakeCircle2d(real *arr, int slices, real ctrX, real ctrY, real r){
+    int i;
+    real radstep = 2 * TNS_PI / (real)slices;
+    real rd = 0;
+    real x, y;
+    for (i = 0; i < slices; i++){
+        x = ctrX + cos(rd) * r;
+        y = ctrY + sin(rd) * r;
+        arr[2 * i] = x;
+        arr[2 * i + 1] = y;
+        rd += radstep;
+    }
+}
+void tnsMakeArc2d(real *arr, int slices, real ctrX, real ctrY, real r, real rad_begin, real rad_end){
+    int i;
+    real radstep = (rad_end - rad_begin) / (real)slices;
+    real rd = rad_begin;
+    real x, y;
+    for (i = 0; i <= slices; i++){
+        x = ctrX + cos(rd) * r;
+        y = ctrY + sin(rd) * r;
+        arr[2 * i] = x;
+        arr[2 * i + 1] = y;
+        rd += radstep;
+    }
+}
+
+void tnsMakeBridgedIndex(unsigned int *result, int num, int revert, int begin){
+    int i;
+    if (!revert){
+        for (i = 0; i < num; i++){
+            result[i * 2] = begin + i;
+            result[i * 2 + 1] = begin + i + num;
+        }
+    }else{
+        for (i = 0; i < num; i++){
+            result[i * 2] = begin + i;
+            result[i * 2 + 1] = begin - i + num * 2;
+        }
+    }
+}
+
+void tnsMakeRing2d(real *arr, int *index, int slices, real ctrX, real ctrY, real r1, real r2){
+    tnsMakeCircle2d(arr, slices, ctrX, ctrY, r1);
+    tnsMakeCircle2d(&arr[slices*2], slices, ctrX, ctrY, r2);
+    tnsMakeBridgedIndex(index, slices, 0, 0);
+    index[slices*2]=0; index[slices*2+1]=slices;
+}
+
+void tnsMakeLinerGradient3d(real *arr, int num_points, real r0, real g0, real b0, real r1, real g1, real b1){
+    int i = 0;
+    real sr = (r1 - r0) / (real)num_points, sg = (g1 - g0) / (real)num_points, sb = (b1 - b0) / (real)num_points;
+    for (i; i < num_points; i++){
+        int a = 3 * i;
+        arr[a] = r0 + sr * i;
+        arr[a + 1] = g0 + sg * i;
+        arr[a + 2] = b0 + sb * i;
+    }
+}
+void tnsMakeLinerGradient4d(real *arr, int num_points, real r0, real g0, real b0, real a0, real r1, real g1, real b1, real a1){
+    int i = 0;
+    real sr = (r1 - r0) / (real)num_points, sg = (g1 - g0) / (real)num_points, sb = (b1 - b0) / (real)num_points, sa = (a1 - a0) / (real)num_points;
+    for (i; i < num_points; i++){
+        int a = 4 * i;
+        arr[a] = r0 + sr * i;
+        arr[a + 1] = g0 + sg * i;
+        arr[a + 2] = b0 + sb * i;
+        arr[a + 3] = a0 + sa * i;
+    }
+}
+void tnsMakeLinerGradient3dv(real *arr, int num_points, real *rgb0, real *rgb1){
+    int i = 0;
+    real sr = (rgb1[0] - rgb0[0]) / (real)num_points, sg = (rgb1[1] - rgb0[1]) / (real)num_points, sb = (rgb1[2] - rgb0[2]) / (real)num_points;
+    for (i; i < num_points; i++){
+        int a = 3 * i;
+        arr[a] = rgb0[0] + sr * i;
+        arr[a + 1] = rgb0[1] + sg * i;
+        arr[a + 2] = rgb0[2] + sb * i;
+    }
+}
+void tnsMakeLinerGradient4dv(real *arr, int num_points, real *rgb0, real *rgb1){
+    int i = 0;
+    real sr = (rgb1[0] - rgb0[0]) / (real)(num_points - 1), sg = (rgb1[1] - rgb0[1]) / (real)(num_points - 1), sb = (rgb1[2] - rgb0[2]) / (real)(num_points - 1), sa = (rgb1[3] - rgb0[3]) / (real)(num_points - 1);
+    for (i; i < num_points; i++){
+        int a = 4 * i;
+        arr[a] = rgb0[0] + sr * i;
+        arr[a + 1] = rgb0[1] + sg * i;
+        arr[a + 2] = rgb0[2] + sb * i;
+        arr[a + 3] = rgb0[3] + sa * i;
+    }
+}
+
+void tnsMakeFoucsSquare(int L, int R, int U, int B, int W){
+    int w = W;
+    //int al = Len + w;
+    real v[16];
+
+    //v[0] = L - w; v[1] = U - l;
+    //v[2] = L - w; v[3] = U + w;
+    //v[4] = L + l; v[4] = U + w;
+    //v[6] = L + l; v[7] = U - w;
+    //v[8] = L + w; v[9] = U - w;
+    //v[10] = L + w; v[11] = U - l;
+
+    //v[12] = R - l; v[13] = U + w;
+    //v[14] = R + w; v[15] = U + w;
+    //v[16] = R + w; v[17] = U - l;
+    //v[18] = R - w; v[19] = U - l;
+    //v[20] = R - w; v[21] = U - w;
+    //v[22] = R - l; v[23] = U - w;
+
+    tnsMakeQuad2d(v, L, U, R, U, R, B, L, B);
+    tnsVertexArray2d(v, 4);
+    tnsPackAs(GL_LINE_LOOP);
+    tnsMakeQuad2d(&v[8], L + W, U - W, R - W, U - W, R - W, B + W, L + W, B + W);
+    tnsVertexArray2d(&v[8], 4);
+    tnsPackAs(GL_LINE_LOOP);
+}
+
+void tnsDrawFloor(int Size, int Span, int *ShowAxis){
+    int i = 0;
+    int Lim = Span * 2 + 1;
+    int Dist = Size * Span;
+
+    for (i; i < Lim; i++){
+        if (i == Span && ShowAxis[0]) continue;
+        tnsVertex3d(-Dist, i * Size - Dist, 0);
+        tnsVertex3d(Dist, i * Size - Dist, 0);
+    }
+
+    for (i = 0; i < Lim; i++){
+        if (i == Span && ShowAxis[1]) continue;
+        tnsVertex3d(i * Size - Dist, -Dist, 0);
+        tnsVertex3d(i * Size - Dist, Dist, 0);
+    }
+
+    tnsPackAs(GL_LINES);
+
+    if (ShowAxis[0]){
+        tnsColor4d(1, 0, 0, 1);
+        tnsVertex3d(-Dist, 0, 0);
+        tnsVertex3d(Dist, 0, 0);
+        tnsPackAs(GL_LINES);
+    }
+    if (ShowAxis[1]){
+        tnsColor4d(0, 1, 0, 1);
+        tnsVertex3d(0, -Dist, 0);
+        tnsVertex3d(0, Dist, 0);
+        tnsPackAs(GL_LINES);
+    }
+    if (ShowAxis[2]){
+        tnsColor4d(0, 0, 1, 1);
+        tnsVertex3d(0, 0, -Dist);
+        tnsVertex3d(0, 0, Dist);
+        tnsPackAs(GL_LINES);
+    }
+}

+ 401 - 0
source/lagui/la_tns_mesh.c

@@ -0,0 +1,401 @@
+#include "la_5.h"
+#include <math.h>
+
+extern tnsMain *T;
+
+
+tnsEdgeHash* tnsCreateEdgeHash(int OptionalInitialVertCount){
+    tnsEdgeHash*eh=memAcquireSimple(sizeof(tnsEdgeHash));
+    eh->max=OptionalInitialVertCount;
+    if(eh->max<16) eh->max=16;
+    arrInitLength(&eh->vl,eh->max,&eh->max, sizeof(tnsEdgeHashVert));
+    return eh;
+}
+void tnsDestroyEdgeHash(tnsEdgeHash* eh){
+    for(int i=0;i<eh->max;i++){
+        tnsEdgeHashVert* ehv=&eh->vl[i];
+        if(ehv->e) free(ehv->e);
+    }
+    if(eh->vl) free(eh->vl);
+    memFree(eh);
+}
+void tnsEdgeHashAddVertPair(tnsEdgeHash* eh, int v1, int v2){
+    if(v1==v2) return; if(v1>v2) LA_SWAP(int, v1,v2); if(v1>=eh->max) return;
+    tnsEdgeHashVert* ehv=&eh->vl[v1];
+    if(!ehv->e) arrInitLength(&ehv->e,1,&ehv->max, sizeof(tnsEdgeHashEdge));
+    else arrEnsureLength(&ehv->e, ehv->next, &ehv->max, sizeof(tnsEdgeHashEdge));
+    for(int i=0;i<ehv->next;i++){ if(ehv->e[i].tv==v2) return; }
+    ehv->e[ehv->next].tv=v2;
+    ehv->next++;
+}
+tnsEdgeHashEdge* tnsEdgeHashGetEdge(tnsEdgeHash* eh, int v1, int v2){
+    if(v1==v2) return 0; if(v1>v2) LA_SWAP(int, v1,v2); if(v1>=eh->max) return 0;
+    tnsEdgeHashVert* ehv=&eh->vl[v1];
+    for(int i=0;i<ehv->next;i++){ if(ehv->e[i].tv==v2) return &ehv->e[i]; }
+    return 0;
+}
+
+void tnsInitMesh(tnsMeshObject* mo, int Initialv, int Initiale, int Initialf){
+    arrInitLength(&mo->v, Initialv, &mo->maxv, sizeof(tnsVert));
+    arrInitLength(&mo->e, Initiale, &mo->maxe, sizeof(tnsEdge));
+    arrInitLength(&mo->f, Initialf, &mo->maxf, sizeof(tnsFace));
+}
+tnsVert* tnsFillVertI(tnsMeshObject* mo, int index, real x, real y, real z){
+    arrEnsureLength(&mo->v, index, &mo->maxv, sizeof(tnsVert));
+    mo->v[index].p[0]=x;
+    mo->v[index].p[1]=y;
+    mo->v[index].p[2]=z;
+    return &mo->v[index];
+}
+tnsVert* tnsFillVert(tnsMeshObject* mo, real x, real y, real z){
+    int index=mo->totv; mo->totv++;
+    return tnsFillVertI(mo, index, x,y,z);
+}
+tnsFace* tnsFillFace(tnsMeshObject* mo, int vertcount, ...){
+    arrEnsureLength(&mo->f, mo->totf, &mo->maxf, sizeof(tnsFace));
+    arrInitLength(&mo->f[mo->totf].loop, vertcount, &mo->f[mo->totf].looplen, sizeof(int));
+    va_list list; va_start(list, vertcount); int id=va_arg(list, int); if(id==-1){ va_end(list); mo->totf++; return &mo->f[mo->totf-1]; }
+    for(int i=0;i<vertcount;i++){ mo->f[mo->totf].loop[i]=id; id=va_arg(list, int); }
+    va_end(list);
+    mo->totf++; return &mo->f[mo->totf-1];
+}
+void tnsFillFaceLoop(tnsFace* f, int i, int v){ f->loop[i]=v; }
+
+void tnsInitMeshPlane(tnsMeshObject* mo, real size){
+    tnsInitMesh(mo, 4,0,1);
+    tnsFillVert(mo, size, size,0); tnsFillVert(mo,-size, size,0);
+    tnsFillVert(mo,-size,-size,0); tnsFillVert(mo, size,-size,0);
+    tnsFillFace(mo, 4, 0,1,2,3);
+    mo->v[0].flags|=TNS_MESH_FLAG_SELECTED;
+    mo->v[1].flags|=TNS_MESH_FLAG_SELECTED;
+    mo->v[2].flags|=TNS_MESH_FLAG_SELECTED;
+    mo->v[3].flags|=TNS_MESH_FLAG_SELECTED;
+    tnsMMeshEnsureSelectionFromVert(mo);
+}
+
+void tnsTrangulateFaceSimple(tnsMeshObject* mo, tnsFace* f, int* ebuf){
+    for(int i=0;i<f->looplen-2;i++){
+        ebuf[i*3]=f->loop[0];
+        ebuf[i*3+1]=f->loop[i+1];
+        ebuf[i*3+2]=f->loop[i+2];
+    }
+}
+void tnsTrangulateFaceSimpleM(tnsMeshObject* mo, tnsMFace* mf, int* ebuf){
+    tnsMVert* mv=0,*mvs; int i=0;
+    for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
+        laListItemPointer* next=lip->pNext; if(!next) next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
+        if(next==mf->l.pLast){ break; }
+        mvs=tnsMMeshEdgeStartingVert(me0,me1);
+        if(!mv) mv=mvs;
+        ebuf[i*3]=mv->i; tnsMVert*mm=tnsMMeshEdgeAnotherVert(me0,mvs);
+        ebuf[i*3+1]=mm->i;
+        ebuf[i*3+2]=tnsMMeshEdgeAnotherVert(me1,mm)->i; i++;
+    }
+}
+int* tnsGetTriangulatedBatch(tnsMeshObject* mo, int* totelem){
+    int tottri=0;
+    if(mo->Mode==TNS_MESH_OBJECT_MODE){ for(int i=0;i<mo->totf;i++){ tottri+=(mo->f[i].looplen-2); } }
+    else{ for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ tottri+=mf->looplen-2; } }
+    if(!tottri) return 0;
+    int* ebuf=calloc(1,sizeof(int)*tottri*3); int* pebuf=ebuf;
+    if(mo->Mode==TNS_MESH_OBJECT_MODE){ for(int i=0;i<mo->totf;i++){ tnsTrangulateFaceSimple(mo, &mo->f[i], pebuf); pebuf+=(mo->f[i].looplen-2)*3; } }
+    else{ for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ tnsTrangulateFaceSimpleM(mo, mf, pebuf); pebuf+=(mf->looplen-2)*3; } }
+    *totelem = tottri;
+    return ebuf;
+}
+float* tnsGetDrawingVertArray(tnsMeshObject* mo, int* r_totv, int DoIdColors, float** idcolors, int DoEditModeColors, float** editcolors){
+    if(!mo->totv&&!mo->totmv) return 0;
+    int totv=mo->Mode==TNS_MESH_EDIT_MODE?mo->totmv:mo->totv; *r_totv=totv;
+    float* p=calloc(1,totv*3*sizeof(float));
+    if(DoIdColors){ (*idcolors)=calloc(1,totv*3*sizeof(float)); }
+    if(DoEditModeColors){ (*editcolors)=calloc(1,totv*4*sizeof(float)); }
+    if(mo->Mode==TNS_MESH_OBJECT_MODE){ for(int i=0;i<totv;i++){ p[i*3]=mo->v[i].p[0]; p[i*3+1]=mo->v[i].p[1]; p[i*3+2]=mo->v[i].p[2]; } }
+    else{ for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ int i=mv->i;
+        p[i*3]=mv->p[0]; p[i*3+1]=mv->p[1]; p[i*3+2]=mv->p[2];
+        if(DoIdColors){
+            int id=i+1;
+            real r=(real)((id & 0x000000FF)>>0)/255.0; real g=(real)((id & 0x0000FF00)>>8)/255.0; real b=(real)((id & 0x00FF0000)>>16)/255.0;
+            (*idcolors)[i*3]=r; (*idcolors)[i*3+1]=g; (*idcolors)[i*3+2]=b;
+        }
+        if(DoEditModeColors){
+            real* c=(mv->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SVERTEX):laAccentColor(LA_BT_VERTEX);
+            (*editcolors)[i*4]=c[0]; (*editcolors)[i*4+1]=c[1]; (*editcolors)[i*4+2]=c[2]; (*editcolors)[i*4+3]=c[3];
+        }
+    } }
+    return p;
+}
+int* tnsGetEdgeBatch(tnsMeshObject* mo){
+    if(!mo->totme) return 0;
+    int* ebuf=calloc(1,sizeof(int)*mo->totme*2); int* pebuf=ebuf; int i=0;
+    for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ ebuf[i*2]=me->vl->i; ebuf[i*2+1]=me->vr->i; i++; }
+    return ebuf;
+}
+
+void tnsInvaliateMeshBatch(tnsMeshObject* mo){
+    if(mo->Base.Type!=TNS_OBJECT_MESH) return;
+    if(mo->Batch) tnsDeleteBatch(mo->Batch); mo->Batch=0;
+}
+void tnsRegenerateMeshBatch(tnsMeshObject* mo){
+    if(!mo) return;
+    if(mo->Batch) tnsDeleteBatch(mo->Batch); mo->Batch=0;
+    real meshcolor[4]={0.8,0.8,0.8,0.6};
+
+    int tottri; int* elem = tnsGetTriangulatedBatch(mo, &tottri);
+    float* idcolors=0,*editcolors=0; int docolors=mo->Mode==TNS_MESH_EDIT_MODE;
+    int totv;
+    float* v = tnsGetDrawingVertArray(mo,&totv,docolors,&idcolors,docolors,&editcolors);
+    if(!v){ if(elem){free(elem);} return; }
+    mo->Batch = tnsCreateBatch(totv, 3, v, 0, 0, 4, editcolors);
+    tnsBatchCommand*c=tnsCreateCommand(mo->Batch, "body", tottri, 3, GL_TRIANGLES, elem, 0);
+    tnsCommandUseUniformColor(c,meshcolor);
+    free(elem); free(v);
+
+    if(mo->Mode==TNS_MESH_EDIT_MODE){
+        elem=tnsGetEdgeBatch(mo); if(elem) {
+            c= tnsCreateCommand(mo->Batch, "lines", mo->totme, 2, GL_LINES, elem, 0); free(elem);
+            //tnsCommandUseUniformColor(c, laAccentColor(LA_BT_EDGE));
+        }
+        c= tnsCreateCommand(mo->Batch, "verts", mo->totmv, 3, GL_POINTS, 0, 0);
+        c= tnsCreateCommand(mo->Batch, "verts_select", mo->totmv, 3, GL_POINTS, 0, 1);
+        tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
+    }
+    if(idcolors) free(idcolors); if(editcolors) free(editcolors);
+}
+void tnsEnsureMeshBatch(tnsMeshObject* mo){
+    if(mo->Base.Type!=TNS_OBJECT_MESH) return;
+    if(mo->Batch) return;
+    tnsRegenerateMeshBatch(mo);
+}
+void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsSelection, tnsMeshObject* Active){
+    tnsEnsureMeshBatch(mo);
+    if(DrawAsSelection){
+        if(mo->Base.Flags&TNS_OBJECT_FLAGS_SELECTED && mo->Mode!=TNS_MESH_EDIT_MODE){
+            real* color=(Active==mo)?laAccentColor(LA_BT_TEXT):laAccentColor(LA_BT_NORMAL);
+            tnsDrawBatch(mo->Batch, "body", color, 0);
+        }
+    }else{
+        if(T->BindedShader==T->SelectionShader){
+            int i=mo->Base.SelectID; real color[4]={0,0,0,1};
+            color[0]=(real)((i & 0x000000FF)>>0)/255.0;
+            color[1]=(real)((i & 0x0000FF00)>>8)/255.0;
+            color[2]=(real)((i & 0x00FF0000)>>16)/255.0;
+            tnsDrawBatch(mo->Batch,"body",color,0);
+        }else tnsDrawBatch(mo->Batch,0,0,0);
+    }
+}
+
+tnsMFace* tnsMMeshNewFace(tnsMeshObject* mo){ tnsMFace* mf=memAcquireSimple(sizeof(tnsMFace)); mf->i=mo->totmf; mo->totmf++; lstAppendItem(&mo->mf,mf); return mf; }
+tnsMEdge* tnsMMeshNewEdge(tnsMeshObject* mo){ tnsMEdge* me=memAcquireSimple(sizeof(tnsMEdge)); me->i=mo->totme; mo->totme++; lstAppendItem(&mo->me,me); return me; }
+tnsMVert* tnsMMeshNewVert(tnsMeshObject* mo){ tnsMVert* mv=memAcquireSimple(sizeof(tnsMVert)); mv->i=mo->totmv; mo->totmv++; lstAppendItem(&mo->mv,mv); return mv; }
+void tnsMMeshEdgeAssignVerts(tnsMEdge* me,tnsMVert* mv1,tnsMVert* mv2){
+    if(me->vl||me->vr){ return; }  //if((me->vl==mv1&&me->vr=mv2) || (me->vl==mv2&&me->vr=mv1))
+    me->vl=mv1; me->vr=mv2;
+    lstAppendPointer(&me->vl->elink,me); lstAppendPointer(&me->vr->elink,me);
+}
+tnsMVert* tnsMMeshEdgeShareVert(tnsMEdge* me0, tnsMEdge* me1){
+    if(me0->vl==me1->vl || me0->vl==me1->vr) return me0->vl;
+    if(me0->vr==me1->vl || me0->vr==me1->vr) return me0->vr;
+    return 0;
+}
+tnsMVert* tnsMMeshEdgeAnotherVert(tnsMEdge* me, tnsVert* v){
+    if(me->vl==v) return me->vr; if(me->vr==v) return me->vl;
+    return 0;
+}
+tnsMVert* tnsMMeshEdgeStartingVert(tnsMEdge* me0, tnsMEdge* me1){
+    tnsMVert* sv=tnsMMeshEdgeShareVert(me0,me1); if(!sv) return 0;
+    return tnsMMeshEdgeAnotherVert(me0, sv);
+}
+void tnsMMeshFaceAddEdge(tnsMFace* mf, tnsMEdge* me){
+    lstAppendPointer(&mf->l, me); mf->looplen++;
+    if(!me->fl) me->fl=mf; elif(!me->fr) me->fr=mf;
+}
+tnsMFace* tnsMMeshFaceHasVert(tnsMFace* mf, tnsMVert* mv){
+    if(!mf||!mv) return 0; for(laListItemPointer*lip=mf->l.pFirst;lip;lip=lip->pNext){ if(tnsMMeshEdgeAnotherVert(lip->p, mv)) return mf; }
+    return 0;
+}
+tnsMFace* tnsMMeshVertsShareFace(tnsMVert* v1, tnsMVert* v2){
+    tnsMFace* mf=0; for(laListItemPointer*lip=v1->elink.pFirst;lip;lip=lip->pNext){
+        tnsMEdge* me=lip->p; if((mf=tnsMMeshFaceHasVert(me->fl, v2)) || (mf=tnsMMeshFaceHasVert(me->fr, v2))) return mf;
+    } return 0;
+}
+int tnsMMeshSplitFace(tnsMeshObject* mo, tnsMFace* mf, tnsMEdge* me, tnsMFace** r_f1, tnsMFace** r_f2){
+    tnsMEdge* NextE; laListItemPointer* NextLip, *StartLip=0, *EndLip=0; int guard=0;
+    for(laListItemPointer*lip=mf->l.pFirst;lip;lip=NextLip){
+        NextLip=lip->pNext?lip->pNext:mf->l.pFirst; NextE=NextLip->p;
+        if(tnsMMeshEdgeShareVert(me,tnsMMeshEdgeShareVert(NextE,lip->p))){ if(!StartLip) StartLip=lip; else{EndLip=lip; break;} }
+        guard++; if(guard>mf->looplen) return 0; // ve is not across mf.
+    }
+    tnsMFace* f1=tnsMMeshNewFace(mo);
+    for(laListItemPointer*lip=StartLip;lip;lip=NextLip){ NextLip=lip->pNext?lip->pNext:mf->l.pFirst; 
+         if(lip==EndLip){ tnsMMeshFaceAddEdge(f1, me); break; } tnsMMeshFaceAddEdge(f1, lip->p);
+    }
+    tnsMFace* f2=tnsMMeshNewFace(mo);
+    for(laListItemPointer*lip=EndLip;lip;lip=NextLip){ NextLip=lip->pNext?lip->pNext:mf->l.pFirst; 
+         if(lip==StartLip){ tnsMMeshFaceAddEdge(f2, me); break; } tnsMMeshFaceAddEdge(f2, lip->p);
+    }
+    tnsMMeshRemoveFaceOnly(mo, mf);
+    if(r_f1){ *r_f1=f1; }  if(r_f2){ *r_f2=f2; }
+    return 1;
+}
+tnsMEdge* tnsMMeshMakeEdge(tnsMeshObject* mo, tnsMVert* v1, tnsMVert* v2){
+    for(laListItemPointer*lip=v1->elink.pFirst;lip;lip=lip->pNext){ if(tnsMMeshEdgeAnotherVert(lip->p, v1)==v2) return lip->p; }
+    // for(laListItemPointer*lip=v2->elink.pFirst;lip;lip=lip->pNext){ if(tnsMMeshEdgeAnotherVert(lip->p, v2)==v1) return lip->p; } shouldn't need.
+    tnsMFace* mf=tnsMMeshVertsShareFace(v1,v2);
+    tnsMEdge* me=tnsMMeshNewEdge(mo); tnsMMeshEdgeAssignVerts(me, v1, v2);
+    if(mf){ tnsMMeshSplitFace(mo, mf, me, 0,0); }
+    return me;
+}
+int tnsMMeshFaceMatches(tnsMFace* mf, int ecount, ...){
+    if(!mf||mf->looplen!=ecount) return 0;
+    va_list list; va_start(list, ecount);
+    for(int i=0;i<ecount;i++){
+        tnsMEdge* me=va_arg(list, tnsMEdge*); int found=0;
+        for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
+            if(lip->p==me){ found=1; break; }
+        }
+        if(!found){ va_end(list); return 0; }
+    }
+    va_end(list); return 1;
+}
+tnsMFace* tnsMMeshMakeFace4v(tnsMeshObject* mo, tnsVert* v1,tnsVert* v2,tnsVert* v3,tnsVert* v4){
+    tnsMEdge* e1=tnsMMeshMakeEdge(mo,v1,v2); tnsMEdge* e2=tnsMMeshMakeEdge(mo,v2,v3);
+    tnsMEdge* e3=tnsMMeshMakeEdge(mo,v3,v4); tnsMEdge* e4=tnsMMeshMakeEdge(mo,v4,v1);
+    if(tnsMMeshFaceMatches(e1->fl,4,e1,e2,e3,e4)) return e1->fl; if(tnsMMeshFaceMatches(e1->fr,4,e1,e2,e3,e4)) return e1->fr; //should not need more
+    if((e1->fl&&e1->fr) || (e2->fl&&e2->fr) || (e3->fl&&e3->fr) || (e4->fl&&e4->fr)) return 0;
+    tnsMFace* mf=tnsMMeshNewFace(mo);
+    tnsMMeshFaceAddEdge(mf,e1); tnsMMeshFaceAddEdge(mf,e2);
+    tnsMMeshFaceAddEdge(mf,e3); tnsMMeshFaceAddEdge(mf,e4);
+    return mf;
+}
+void tnsMMeshRemoveFaceOnly(tnsMeshObject* mo, tnsMFace* mf){
+    if(!mf) return; tnsMEdge* me;
+    while(me=lstPopPointerLeave(&mf->l)){ if(me->fl==mf) me->fl=0; elif(me->fr==mf) me->fr=0; }
+    lstRemoveItem(&mo->mf,mf); memLeave(mf); mo->totmf--;
+}
+void tnsMMeshRemoveEdgeFace(tnsMeshObject* mo, tnsMEdge* me){
+    if(!me) return;
+    tnsMMeshRemoveFaceOnly(mo, me->fl); tnsMMeshRemoveFaceOnly(mo, me->fr);
+    lstRemovePointerLeave(&me->vl->elink, me); lstRemovePointerLeave(&me->vr->elink, me);
+    lstRemoveItem(&mo->me,me); memLeave(me); mo->totme--;
+}
+void tnsMMeshRemoveVertEdgeFace(tnsMeshObject* mo, tnsMVert* mv){
+    if(!mv) return; tnsMEdge* me;
+    while(me=lstPopPointerLeave(&mv->elink)){ tnsMMeshRemoveEdgeFace(mo,me); }
+    lstRemoveItem(&mo->mv,mv); memLeave(mv); mo->totmv--;
+}
+
+void tnsMMeshRefreshIndex(tnsMeshObject* mo){
+    int i;
+    i=0; for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->i=i; i++; } mo->totmv=i;
+    i=0; for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->i=i; i++; } mo->totme=i;
+    i=0; for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->i=i; i++; } mo->totmf=i;
+}
+
+void tnsClearMesh(tnsMeshObject* mo){
+    arrFree(&mo->v, &mo->maxv); mo->totv=0;
+    arrFree(&mo->e, &mo->maxe); mo->tote=0;
+    for(int i=0;i<mo->totf;i++){ if(mo->f[i].loop) free(mo->f[i].loop); }
+    arrFree(&mo->f, &mo->maxf); mo->totf=0;
+}
+void tnsClearMMesh(tnsMeshObject* mo){
+    tnsMFace* mf; tnsMEdge* me; tnsMVert* mv;
+    while(mf=lstPopItem(&mo->mf)){ while(lstPopPointerLeave(&mf->l)); memLeave(mf); }
+    while(me=lstPopItem(&mo->me)){ memLeave(me); }
+    while(mv=lstPopItem(&mo->mv)){ while(lstPopPointerLeave(&mv->elink)); memLeave(mv); }
+    mo->totmv=mo->totme=mo->totmf=0;
+}
+
+void tnsMMeshFromMesh(tnsMeshObject* mo){
+    tnsEdgeHash* eh=tnsCreateEdgeHash(mo->totv); //mo->totmv=mo->totv; mo->totme=mo->tote; mo->totmf=mo->totf;
+    for(int i=0;i<mo->totf;i++){
+        tnsFace* f=&mo->f[i];
+        for(int j=0;j<f->looplen-1;j++){ tnsEdgeHashAddVertPair(eh, f->loop[j], f->loop[j+1]); }
+        tnsEdgeHashAddVertPair(eh, f->loop[f->looplen-1], f->loop[0]);
+    }
+    for(int i=0;i<eh->max;i++){
+        tnsEdgeHashVert* ehv=&eh->vl[i];
+        for(int j=0;j<ehv->next;j++){ tnsMEdge*me=tnsMMeshNewEdge(mo); ehv->e[j].me=me; }
+    }
+    for(int i=0;i<mo->totv;i++){ tnsVert*v=&mo->v[i]; tnsMVert*mv=tnsMMeshNewVert(mo); eh->vl[i].mv=mv;
+        mv->p[0]=mo->v[i].p[0]; mv->p[1]=mo->v[i].p[1]; mv->p[2]=mo->v[i].p[2]; mv->flags=mo->v[i].flags; }
+    for(int i=0;i<mo->totf;i++){
+        tnsFace* f=&mo->f[i]; tnsMFace* mf=tnsMMeshNewFace(mo); mf->flags=f->flags;
+        for(int j=0;j<f->looplen;j++){ int v2=j+1; if(j==f->looplen-1) v2=0;
+            tnsEdgeHashEdge* ehe=tnsEdgeHashGetEdge(eh,f->loop[j],f->loop[v2]);
+            tnsMEdge* me=ehe->me; tnsMMeshEdgeAssignVerts(me,eh->vl[f->loop[j]].mv,eh->vl[f->loop[v2]].mv);
+            tnsMMeshFaceAddEdge(mf,me);
+        }
+    }
+    tnsMMeshEnsureSelectionFromVert(mo);
+    tnsDestroyEdgeHash(eh);
+}
+void tnsMeshFromMMesh(tnsMeshObject* mo){
+    tnsClearMesh(mo); 
+    tnsInitMesh(mo, mo->totmv, 0, mo->totmf); int i=0;
+    /* Vertex index should already correct. */
+    //for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->i=i; i++; }
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ tnsVert* v=tnsFillVert(mo, mv->p[0], mv->p[1], mv->p[2]); v->flags=mv->flags; }
+    for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ tnsFace* f=tnsFillFace(mo, mf->looplen, -1);  f->flags=mf->flags;
+        int j=0; for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){
+            laListItemPointer* next=lip->pNext; if(!next) next=mf->l.pFirst; tnsMEdge* me0=lip->p, *me1=next->p;
+            tnsFillFaceLoop(f, j, tnsMMeshEdgeStartingVert(me0,me1)->i); j++;
+        }
+    }
+    mo->totv=mo->totmv; mo->totf=mo->totmf;
+    tnsClearMMesh(mo);
+}
+
+void tnsMeshEnterEditMode(tnsMeshObject* mo){
+    if(mo->Mode==TNS_MESH_EDIT_MODE || mo->mv.pFirst) return;
+    tnsMMeshFromMesh(mo);
+    mo->Mode = TNS_MESH_EDIT_MODE;
+    tnsInvaliateMeshBatch(mo);
+}
+void tnsMeshLeaveEditMode(tnsMeshObject* mo){
+    if(mo->Mode==TNS_MESH_OBJECT_MODE) return;
+    tnsMeshFromMMesh(mo);
+    mo->Mode = TNS_MESH_OBJECT_MODE;
+    tnsInvaliateMeshBatch(mo);
+}
+
+int tnsMMeshAnySelected(tnsMeshObject* mo){
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(mv->flags&TNS_MESH_FLAG_SELECTED) return 1; }
+    for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(me->flags&TNS_MESH_FLAG_SELECTED) return 1; }
+    for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ if(mf->flags&TNS_MESH_FLAG_SELECTED) return 1; } return 0;
+}
+void tnsMMeshDeselectAll(tnsMeshObject* mo){
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_SELECTED); }
+    for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED); }
+    for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags&=(~TNS_MESH_FLAG_SELECTED); }
+}
+void tnsMMeshSelectAll(tnsMeshObject* mo){
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags|=TNS_MESH_FLAG_SELECTED; }
+    for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags|=TNS_MESH_FLAG_SELECTED; }
+    for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ mf->flags|=TNS_MESH_FLAG_SELECTED; }
+}
+void tnsMMeshSelectVert(tnsMeshObject* mo, tnsMVert* mv, int select, int toggle){
+    if(!mo) return;
+    if(toggle) tnsMMeshSelectVert(mo,mv,(mv->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
+    elif(select) mv->flags|=TNS_MESH_FLAG_SELECTED; else mv->flags&=(~TNS_MESH_FLAG_SELECTED);
+}
+void tnsMMeshEnsureSelectionFromVert(tnsMeshObject* mo){
+    for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ me->flags&=(~TNS_MESH_FLAG_SELECTED);
+        if(me->vl->flags&me->vr->flags&TNS_MESH_FLAG_SELECTED) me->flags|=TNS_MESH_FLAG_SELECTED; 
+    }
+    for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){ int sel=1; mf->flags&=(~TNS_MESH_FLAG_SELECTED);
+        for(laListItemPointer* lip=mf->l.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; if(!(me->flags&TNS_MESH_FLAG_SELECTED)){ sel=0; break; } }
+        if(sel){ mf->flags|=TNS_MESH_FLAG_SELECTED; }
+    }
+}
+
+tnsMeshObject *tnsCreateMeshPlane(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size){
+    tnsMeshObject *mo; tnsWorld *w = &T->World;
+
+    mo = memAcquireHyper(sizeof(tnsMeshObject));
+    tnsInitObjectBase(&mo->Base, under, Name, TNS_OBJECT_MESH, AtX, AtY, AtZ, 0, 0, 0, 1.0f, TNS_ROTATION_XYZ_EULER, 1.0f);
+    tnsInitMeshPlane(mo, size);
+    tnsInvaliateMeshBatch(mo);
+
+    return mo;
+}
+

+ 2085 - 0
source/lagui/la_util.c

@@ -0,0 +1,2085 @@
+/*
+NUL4.0 - Nick's Best - www.nicksbest.com
+Author(s):WuYiming - xp8110@outlook.com
+
+Want to join the development?
+Append your name in the author list above.
+Send feedback to la_support@nicksbest.com
+*/
+#define _CRT_SEQURE_NO_WARNINGS
+#include "la_util.h"
+#include "la_interface.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+laSafeStringCollection SSC;
+
+extern LA MAIN;
+
+#define BYTE unsigned char
+
+uint32_t laToUnicode(const unsigned char* ch, int* advance){
+    if((*ch)<0x80) { *advance=1; return *ch; }
+    uint32_t u=0;
+    if(((*ch)>>5)==0x06){ *advance=2; u|=((*(ch+1))&0x3f)|((*(ch)&0x1f)<<6); return u; }
+    if(((*ch)>>4)==0x0e){ *advance=3; u|=((*(ch+2))&0x3f)|((*(ch+1)&0x3f)<<6)|((*(ch)&0x0f)<<12); return u; }
+    if(((*ch)>>3)==0x1e){ *advance=4; u|=((*(ch+3))&0x3f)|((*(ch+2)&0x3f)<<6)|((*(ch+1)&0x3f)<<12)|((*(ch)&0x07)<<18); return u; }
+    *advance=1; return '?';
+}
+int laToUTF8(const uint32_t ch, char* out, char** next){
+    if(ch>=0x10000){ out[0]=0xf0|(ch>>18); out[1]=0x80|(0x3f&(ch>>12)); out[2]=0x80|(0x3f&(ch>>6)); out[3]=0x80|(0x3f&ch); (*next)+=4;}
+    elif(ch>=0x800){ out[0]=0xe0|(ch>>12); out[1]=0x80|(0x3f&(ch>>6)); out[2]=0x80|(0x3f&ch); (*next)+=3;}
+    elif(ch>=0x80){ out[0]=0xc0|(ch>>6); out[1]=0x80|(0x3f&ch); (*next)+=2;}
+    else { if(!ch){return 0;} out[0]=ch&0x7f; (*next)++;} return 1;
+}
+
+int strToUnicode(uint32_t* target, unsigned char* const src){
+    uint32_t UC,adv,i=0; unsigned char* source=src; while(target[i]=laToUnicode(source, &adv)) { source+=adv; i++; } target[i]=0; return i;
+}
+int strToUTF8(unsigned char* target, uint32_t* const src){
+    uint32_t* source=src; unsigned char* out=target; while(laToUTF8(*source, out, &out)){ source++; } *out=0; return out-target;
+}
+int strlenU(uint32_t* str){ int i=0; while(str[i]!=0) i++; return i; }
+int strcpyU(uint32_t* target, uint32_t* const source ){ int i=0; while(source[i]!=0){ target[i]=source[i]; i++; } target[i]=0; }
+int strcatU(uint32_t* target, uint32_t* const source ){ int i=0,tl=strlenU(target); while(source[i]!=0){ target[i+tl]=source[i]; i++; } target[i+tl]=0; }
+
+struct tm *laGetFullTime(){
+    time_t t = time(0);
+    return localtime(&t);
+}
+
+void laRecordTime(laTimeRecorder *tr){
+    //GetSystemTime(&tr->Time);
+    //time(&tr->At);
+    tr->At = clock();
+}
+real laTimeElapsedSecondsf(laTimeRecorder *End, laTimeRecorder *Begin){
+    return (real)(End->At - Begin->At) / CLOCKS_PER_SEC;
+}
+int laTimeElapsedMilliseconds(laTimeRecorder *End, laTimeRecorder *Begin){ return 0;
+    //return (
+    //    End->Time.wMilliseconds - Begin->Time.wMilliseconds +
+    //    (End->Time.wSecond - Begin->Time.wSecond) * 1000 +
+    //    (End->Time.wMinute - Begin->Time.wMinute) * 60000 +
+    //    (End->Time.wHour - Begin->Time.wHour) * 3600000);
+}
+
+void laSetAuthorInfo(char *Name, char *CopyrightString){
+    strSafeSet(&MAIN.Author.Name, Name);
+    strSafeSet(&MAIN.Author.CopyrightString, CopyrightString);
+}
+
+void memCreateNUID(laMemNodeHyper* hi){
+    sprintf(hi->NUID.String, "%hd%02hd%02hd%02hd%02hd%02hd%08X", LA_HYPER_CREATED_TIME(hi), hi);
+}
+
+void memHyperInfo(laPropPack* pp, char* buf){
+    int level=0;void* head=0;
+    laMemNodeHyper* hi; laMemNode* mn;
+    int a=0, count=0, pc;
+    laProp* p=pp->LastPs->p;
+    laPropContainer* c=p->Container;
+    if(c->OtherAlloc){
+        count=lstCountElements(&c->LocalUsers);
+    }else{
+        head=memGetHead(pp->LastPs->UseInstance, &level);
+        if(!level){
+            sprintf(buf,"Not HyperData.\n");
+        }elif(level==1){
+            mn=head; count=lstCountElements(&mn->Users);
+        }elif(level==2){
+            hi=head; count=lstCountElements(&hi->Users);
+        }
+    }
+
+    a=sprintf(buf,"HyperData:\n\tProperty:%s\n\tContainer:%s (%d users)\n",
+        pp->LastPs->p->Identifier, pp->LastPs->p->Container->Identifier, count);
+    
+    if(level==2){
+        sprintf(buf+a,"\tCreated:%hd-%02hd-%02hd %02hd:%02hd:%02hd\n",LA_HYPER_CREATED_TIME(hi));
+    }
+}
+void memMakeHyperData(laMemNodeHyper* hi){
+    struct tm *time;
+    hi->Modified = 1;
+    time = laGetFullTime();
+    //hi->CreatedBy = &MAIN.Author;
+    hi->TimeCreated.Year = time->tm_year + 1900;
+    hi->TimeCreated.Month = time->tm_mon + 1;
+    hi->TimeCreated.Day = time->tm_mday;
+    hi->TimeCreated.Hour = time->tm_hour;
+    hi->TimeCreated.Minute = time->tm_min;
+    hi->TimeCreated.Second = time->tm_sec;
+    //memcpy(&hi->TimeModified, &hi->TimeCreated, sizeof(laTimeInfo));
+    memCreateNUID(hi);
+}
+void memMarkClean(void* HyperUserMem){
+    int hyper=0;
+    laMemNodeHyper* h = memGetHead(HyperUserMem, &hyper);
+    if(hyper!=2) return;
+    h->Modified=0;
+}
+
+void nutFreeMem(void **ptr){
+    //free_total+=1;
+    if (!*ptr) return;
+    free(*ptr);
+    *ptr = 0;
+}
+
+int nutFloatCompare(real l, real r){
+    return (l > r - 0.00005 && l < r + 0.00005);
+}
+
+int nutSameAddress(void *l, void *r){
+    return (l == r);
+}
+
+//===================================================================[list]
+
+void* arrElement(void* head, int i, int size){
+    return ((char*)head+size*i);
+}
+int arrEnsureLength(void** head, int next, int* max, size_t ElementSize){
+    int UseMax=*max;
+    if(next>=UseMax){
+        if(!UseMax){ UseMax=50; }
+        int AllocMax=next>(UseMax*2)?next:(UseMax*2);
+        void* data = CreateNew_Size(ElementSize* AllocMax);
+        if((*head) || next){ memcpy(data, *head, ElementSize*UseMax); }
+        if(*head) free(*head);
+        *head=data;
+        *max= AllocMax;
+        return 1;
+    }
+    return 0;
+}
+int arrInitLength(void** head, int max, int* pmax, size_t ElementSize){
+    if(*head){ free(head); }
+    *head=CreateNew_Size(ElementSize*max);
+    *pmax=max;
+}
+void arrFree(void** head, int* max){ free(*head); *head=0; *max=0; }
+
+void lstPushSingle(void **Head, laListSingle *Item){
+    Item->pNext = *Head;
+    *Head = Item;
+}
+void *lstPopSingle(void **Head, laListSingle *Item){
+    *Head = ((laListSingle *)(*Head))->pNext;
+    Item->pNext = 0;
+    return *Head;
+}
+
+int lstCountElements(laListHandle* Handle){
+    int count=0; if(!Handle) return 0;
+    for(laListItem* i=Handle->pFirst;i;i=i->pNext){count++;}
+    return count;
+}
+
+void lstAppendItem(laListHandle* Handle, void* Item){
+
+	laListItem* li = Item;
+
+	li->pNext = li->pPrev = 0;
+
+	if (!Handle->pFirst) Handle->pFirst = Item;
+
+	if (Handle->pLast) ((laListItem*)Handle->pLast)->pNext = li;
+
+	li->pPrev = Handle->pLast;
+	li->pNext = 0;
+	Handle->pLast = li;
+
+};
+void lstPushItem(laListHandle* Handle, void* Item){
+
+	laListItem* li = Item;
+
+	li->pNext = li->pPrev = 0;
+
+	if (!Handle->pLast) Handle->pLast = Item;
+
+	li->pNext = Handle->pFirst;
+
+	if (Handle->pFirst) ((laListItem*)Handle->pFirst)->pPrev = Item;
+
+	Handle->pFirst = li;
+
+};
+void* lstPopItem(laListHandle* Handle){
+	void* popitem;
+	laListItem* next;
+	if (!Handle->pFirst) return 0;
+
+	popitem = Handle->pFirst;
+
+	next = ((laListItem*)Handle->pFirst)->pNext;
+	if (!next){
+		Handle->pFirst = 0;
+		Handle->pLast = 0;
+	}else{
+		Handle->pFirst = next;
+		if (next) next->pPrev = 0;
+	};
+
+	return popitem;
+};
+int lstHaveItemInList(laListHandle *Handle){
+    if (Handle->pFirst) return 1;
+    return 0;
+};
+
+void lstAppendItem2(laListHandle *Handle, void *Item){
+
+    laListItem2 *li = Item;
+
+    li->pNext = li->pPrev = 0;
+
+    if (!Handle->pFirst) Handle->pFirst = Item;
+
+    if (Handle->pLast) ((laListItem2 *)Handle->pLast)->pNext = li;
+
+    li->pPrev = Handle->pLast;
+    li->pNext = 0;
+    Handle->pLast = li;
+};
+void lstPushItem2(laListHandle *Handle, void *Item){
+
+    laListItem2 *li = Item;
+
+    li->pNext = li->pPrev = 0;
+
+    if (!Handle->pLast) Handle->pLast = Item;
+
+    li->pNext = Handle->pFirst;
+
+    if (Handle->pFirst) ((laListItem2 *)Handle->pFirst)->pPrev = Item;
+
+    Handle->pFirst = li;
+};
+void *lstPopItem2(laListHandle *Handle){
+    void *popitem;
+    laListItem2 *next;
+    if (!Handle->pFirst) return 0;
+
+    popitem = Handle->pFirst;
+
+    next = ((laListItem2 *)Handle->pFirst)->pNext;
+    if (!next){
+        Handle->pFirst = 0;
+        Handle->pLast = 0;
+    }else{
+        Handle->pFirst = next;
+        if (next) next->pPrev = 0;
+    };
+
+    return popitem;
+};
+
+void lstAppendItem3(laListHandle *Handle, void *Item){
+
+    laListItem3 *li = Item;
+
+    li->pNext = li->pPrev = 0;
+
+    if (!Handle->pFirst) Handle->pFirst = Item;
+
+    if (Handle->pLast) ((laListItem3 *)Handle->pLast)->pNext = li;
+
+    li->pPrev = Handle->pLast;
+    li->pNext = 0;
+    Handle->pLast = li;
+};
+void lstPushItem3(laListHandle *Handle, void *Item){
+
+    laListItem3 *li = Item;
+
+    li->pNext = li->pPrev = 0;
+
+    if (!Handle->pLast) Handle->pLast = Item;
+
+    li->pNext = Handle->pFirst;
+
+    if (Handle->pFirst) ((laListItem3 *)Handle->pFirst)->pPrev = Item;
+
+    Handle->pFirst = li;
+};
+void *lstPopItem3(laListHandle *Handle){
+    void *popitem;
+    laListItem3 *next;
+    if (!Handle->pFirst) return 0;
+
+    popitem = Handle->pFirst;
+
+    next = ((laListItem3 *)Handle->pFirst)->pNext;
+    if (!next){
+        Handle->pFirst = 0;
+        Handle->pLast = 0;
+    }else{
+        Handle->pFirst = next;
+        if (next) next->pPrev = 0;
+    };
+
+    return popitem;
+};
+
+void *lstGetTop(laListHandle *Handle){
+    return Handle->pFirst;
+};
+int lstRemoveItem(laListHandle* Handle, laListItem* li) {
+	if (!li->pPrev && Handle->pFirst != li) return;
+
+	if (!li->pPrev) Handle->pFirst = li->pNext;
+	else
+		((laListItem*)li->pPrev)->pNext = li->pNext;
+
+	if (!li->pNext) Handle->pLast = li->pPrev;
+	else
+		((laListItem*)li->pNext)->pPrev = li->pPrev;
+
+	li->pNext = li->pPrev = 0;
+}
+int lstRemoveItem2(laListHandle *Handle, laListItem2 *li){
+    if (!li->pPrev) Handle->pFirst = li->pNext;
+    else
+        ((laListItem2 *)li->pPrev)->pNext = li->pNext;
+
+    if (!li->pNext) Handle->pLast = li->pPrev;
+    else
+        ((laListItem2 *)li->pNext)->pPrev = li->pPrev;
+
+    li->pNext = li->pPrev = 0;
+};
+int lstRemoveItem3(laListHandle *Handle, laListItem2 *li){
+    if (!li->pPrev) Handle->pFirst = li->pNext;
+    else
+        ((laListItem3 *)li->pPrev)->pNext = li->pNext;
+
+    if (!li->pNext) Handle->pLast = li->pPrev;
+    else
+        ((laListItem3 *)li->pNext)->pPrev = li->pPrev;
+
+    li->pNext = li->pPrev = 0;
+};
+
+int lstRemoveSegment(laListHandle *Handle, laListItem *Begin, laListItem *End){
+    if (!Begin->pPrev) Handle->pFirst = End->pNext;
+    else
+        ((laListItem *)Begin->pPrev)->pNext = End->pNext;
+
+    if (!End->pNext) Handle->pLast = Begin->pPrev;
+    else
+        ((laListItem *)End->pNext)->pPrev = Begin->pPrev;
+
+    End->pNext = Begin->pPrev = 0;
+};
+void lstInsertItemBefore(laListHandle *Handle, laListItem *toIns, laListItem *pivot){
+    if (!pivot){
+        lstPushItem(Handle, toIns);
+        return;
+    }
+
+    if (pivot->pPrev){
+        ((laListItem *)pivot->pPrev)->pNext = toIns;
+        toIns->pPrev = pivot->pPrev;
+    }else{
+        Handle->pFirst = toIns;
+    }
+
+    toIns->pNext = pivot;
+    pivot->pPrev = toIns;
+};
+void lstInsertItemAfter(laListHandle *Handle, laListItem *toIns, laListItem *pivot){
+    if (!pivot){
+        lstAppendItem(Handle, toIns);
+        return;
+    }
+
+    if (pivot->pNext){
+        ((laListItem *)pivot->pNext)->pPrev = toIns;
+        toIns->pNext = pivot->pNext;
+    }else{
+        Handle->pLast = toIns;
+    }
+
+    toIns->pPrev = pivot;
+    pivot->pNext = toIns;
+}
+void lstInsertSegmentBefore(laListHandle *Handle, laListItem *Begin, laListItem *End, laListItem *pivot){
+
+    if (pivot->pPrev){
+        ((laListItem *)pivot->pPrev)->pNext = Begin;
+        Begin->pPrev = pivot->pPrev;
+    }else{
+        Handle->pFirst = Begin;
+    }
+
+    End->pNext = pivot;
+    pivot->pPrev = End;
+};
+void lstInsertSegmentAfter(laListHandle *Handle, laListItem *Begin, laListItem *End, laListItem *pivot){
+    if (pivot->pNext){
+        ((laListItem *)pivot->pNext)->pPrev = End;
+        End->pNext = pivot->pNext;
+    }else{
+        Handle->pLast = End;
+    }
+
+    Begin->pPrev = pivot;
+    pivot->pNext = Begin;
+}
+
+void *lstAppendPointerOnly(laListHandle *h, void *p){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = CreateNew(laListItemPointer);
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstAppendPointerSizedOnly(laListHandle *h, void *p, int size){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = calloc(1, size);
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstPushPointerOnly(laListHandle *h, void *p){
+    laListItemPointer *lip = 0;
+    if (!h) return 0;
+    lip = CreateNew(laListItemPointer);
+    lip->p = p;
+    lstPushItem(h, lip);
+    return lip;
+}
+void *lstPushPointerSizedOnly(laListHandle *h, void *p, int size){
+    laListItemPointer *lip = 0;
+    if (!h) return 0;
+    lip = calloc(1, size);
+    lip->p = p;
+    lstPushItem(h, lip);
+    return lip;
+}
+
+int lstHasPointer(laListHandle* h, void *p){
+    laListItemPointer *i; for (i = h->pFirst; i; i = i->pNext){
+        if (i->p == p){return 1;}
+    } return 0;
+}
+void *lstAppendPointer(laListHandle *h, void *p){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = memAcquireSimple(sizeof(laListItemPointer));
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstAppendPointerSized(laListHandle *h, void *p, int size){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = memAcquireSimple(size);
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstPushPointer(laListHandle *h, void *p){
+    laListItemPointer *lip = 0;
+    if (!h) return 0;
+    lip = memAcquireSimple(sizeof(laListItemPointer));
+    lip->p = p;
+    lstPushItem(h, lip);
+    return lip;
+}
+void *lstPushPointerSized(laListHandle *h, void *p, int size){
+    laListItemPointer *lip = 0;
+    if (!h) return 0;
+    lip = memAcquireSimple(size);
+    lip->p = p;
+    lstPushItem(h, lip);
+    return lip;
+}
+
+void *lstAppendPointerStatic(laListHandle *h, laStaticMemoryPool *smp, void *p){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = memStaticAcquire(smp, sizeof(laListItemPointer));
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstAppendPointerStaticSized(laListHandle *h, laStaticMemoryPool *smp, void *p, int size){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = memStaticAcquire(smp, size);
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstPushPointerStatic(laListHandle *h, laStaticMemoryPool *smp, void *p){
+    laListItemPointer *lip = 0;
+    if (!h) return 0;
+    lip = memStaticAcquire(smp, sizeof(laListItemPointer));
+    lip->p = p;
+    lstPushItem(h, lip);
+    return lip;
+}
+void *lstPushPointerStaticSized(laListHandle *h, laStaticMemoryPool *smp, void *p, int size){
+    laListItemPointer *lip = 0;
+    if (!h) return 0;
+    lip = memStaticAcquire(smp, size);
+    lip->p = p;
+    lstPushItem(h, lip);
+    return lip;
+}
+
+void *lstPopPointerOnly(laListHandle *h){
+    laListItemPointer *lip;
+    void *rev = 0;
+    if (!h) return 0;
+    lip = lstPopItem(h);
+    rev = lip ? lip->p : 0;
+    FreeMem(lip);
+    return rev;
+}
+void lstRemovePointerItemOnly(laListHandle *h, laListItemPointer *lip){
+    lstRemoveItem(h, lip);
+    FreeMem(lip);
+}
+void lstRemovePointerOnly(laListHandle *h, void *p){
+    laListItemPointer *i;
+    for (i = h->pFirst; i; i = i->pNext){
+        if (i->p == p){
+            lstRemovePointerItem(h, i);
+            break;
+        }
+    }
+}
+void lstClearPointerOnly(laListHandle *h){
+    laListItemPointer *i;
+    while (h && h->pFirst){
+        lstPopPointer(h);
+    }
+}
+void lstGeneratePointerListOnly(laListHandle *from1, laListHandle *from2, laListHandle *to){
+    laListItemPointer *lip = from2 ? from2->pLast : 0;
+
+    while (lip){
+        lstPushPointer(to, lip->p);
+        lip = lip->pPrev;
+    }
+
+    lip = from1 ? from1->pLast : 0;
+
+    while (lip){
+        lstPushPointer(to, lip->p);
+        lip = lip->pPrev;
+    }
+}
+
+void *lstPopPointer(laListHandle *h){
+    laListItemPointer *lip;
+    void *rev = 0;
+    if (!h) return 0;
+    lip = lstPopItem(h);
+    rev = lip ? lip->p : 0;
+    memFree(lip);
+    return rev;
+}
+void lstRemovePointerItem(laListHandle *h, laListItemPointer *lip){
+    lstRemoveItem(h, lip);
+    memFree(lip);
+}
+void lstRemovePointer(laListHandle *h, void *p){
+    laListItemPointer *i;
+    for (i = h->pFirst; i; i = i->pNext){
+        if (i->p == p){ lstRemovePointerItem(h, i); break; }
+    }
+}
+void lstRemovePointerLeave(laListHandle *h, void *p){
+    laListItemPointer *i;
+    for (i = h->pFirst; i; i = i->pNext){
+        if (i->p == p){ lstRemoveItem(h, i); memLeave(i); break; }
+    }
+}
+void lstClearPointer(laListHandle *h){
+    laListItemPointer *i;
+    while (h && h->pFirst){
+        lstPopPointer(h);
+    }
+}
+void lstGeneratePointerList(laListHandle *from1, laListHandle *from2, laListHandle *to){
+    laListItemPointer *lip = from2 ? from2->pLast : 0;
+
+    while (lip){
+        lstPushPointer(to, lip->p);
+        lip = lip->pPrev;
+    }
+
+    lip = from1 ? from1->pLast : 0;
+
+    while (lip){
+        lstPushPointer(to, lip->p);
+        lip = lip->pPrev;
+    }
+}
+
+void *lstAppendPointerStaticPool(laStaticMemoryPool *mph, laListHandle *h, void *p){
+    laListItemPointer *lip;
+    if (!h) return 0;
+    lip = memStaticAcquire(mph, sizeof(laListItemPointer));
+    lip->p = p;
+    lstAppendItem(h, lip);
+    return lip;
+}
+void *lstPopPointerLeave(laListHandle *h){
+    laListItemPointer *lip;
+    void *rev = 0;
+    if (!h) return 0;
+    lip = lstPopItem(h); memLeave(lip);
+    rev = lip ? lip->p : 0;
+    return rev;
+}
+void lstRemovePointerItemNoFree(laListHandle *h, laListItemPointer *lip){
+    lstRemoveItem(h, lip);
+}
+
+void lstCopyHandle(laListHandle *target, laListHandle *src){
+    target->pFirst = src->pFirst;
+    target->pLast = src->pLast;
+};
+void lstClearHandle(laListHandle *h){
+    h->pFirst = 0;
+    h->pLast = 0;
+}
+void lstClearPrevNext(laListItem *li){
+    li->pNext = 0;
+    li->pPrev = 0;
+}
+
+void lstMoveUp(laListHandle *h, laListItem *li){
+    void *pprev = li->pPrev ? ((laListItem *)li->pPrev)->pPrev : 0;
+    if (!h || !li) return;
+    if (li == h->pFirst) return;
+    else{
+        if (li == h->pLast) h->pLast = li->pPrev;
+        ((laListItem *)li->pPrev)->pNext = li->pNext;
+        ((laListItem *)li->pPrev)->pPrev = li;
+        if (li->pNext) ((laListItem *)li->pNext)->pPrev = li->pPrev;
+        li->pNext = li->pPrev;
+        li->pPrev = pprev;
+        if (pprev) ((laListItem *)pprev)->pNext = li;
+    }
+    if (!li->pPrev) h->pFirst = li;
+}
+void lstMoveDown(laListHandle *h, laListItem *li){
+    void *ppnext = li->pNext ? ((laListItem *)li->pNext)->pNext : 0;
+    if (!h || !li) return;
+    if (li == h->pLast) return;
+    else{
+        if (li == h->pFirst) h->pFirst = li->pNext;
+        ((laListItem *)li->pNext)->pPrev = li->pPrev;
+        ((laListItem *)li->pNext)->pNext = li;
+        if (li->pPrev) ((laListItem *)li->pPrev)->pNext = li->pNext;
+        li->pPrev = li->pNext;
+        li->pNext = ppnext;
+        if (ppnext) ((laListItem *)ppnext)->pPrev = li;
+    }
+    if (!li->pNext) h->pLast = li;
+}
+
+void lstForAllItemsDo(laListDoFunc func, laListHandle *hList){
+    laListItem *it = hList->pFirst;
+    for (; it; it = it->pNext){
+        func(it);
+    }
+};
+void lstForAllItemsDoLNRR(laListNonRecursiveDoFunc func, laListHandle *hList){
+    laListItem *it = hList->pFirst;
+    for (; it; it = it->pNext){
+        func(0, it, 0);
+    }
+};
+void lstForAllItemsDo_DirectFree(laListDoFunc func, laListHandle *hList){
+    laListItem *it;
+    while (it = lstPopItem(hList)){
+        if (func) func(it);
+        FreeMem(it);
+    }
+};
+void lstForAllItemsDo_arg_ptr(laListDoFuncArgp func, laListHandle *hList, void *arg){
+    laListItem *it = hList->pFirst;
+    for (; it; it = it->pNext){
+        func(it, arg);
+    };
+};
+void lstForAllItemsDo_NonRecursive_Root(laListHandle *FirstHandle, laListNonRecursiveDoFunc func, int bFreeItem, void *custom_data, laListCustomDataRemover remover){
+    laListItem *li = 0, *NextLi;
+    laListNonRecursiveRoot root = {0};
+    laListNonRecursiveItem *nrItem = CreateNew(laListNonRecursiveItem);
+
+    nrItem->bFreeList = bFreeItem;
+    nrItem->func = func;
+    nrItem->CustomData = custom_data;
+    nrItem->remover = remover;
+    lstCopyHandle(&nrItem->handle, FirstHandle);
+
+    lstAppendItem(&root.NSItems, nrItem);
+
+    while (lstHaveItemInList(&root.NSItems)){
+        nrItem = lstPopItem(&root.NSItems);
+
+        for (li = nrItem->handle.pFirst; li /*!=nrItem->handle.pLast*/; li = NextLi){
+            if (nrItem->func) nrItem->func(&root, li, custom_data);
+            NextLi = li->pNext;
+            if (nrItem->bFreeList){
+                laListItem *fli = li;
+                FreeMem(fli);
+            }
+            if (li == nrItem->handle.pLast) break;
+        }
+        if (nrItem->remover) nrItem->remover(nrItem->CustomData);
+        FreeMem(nrItem);
+    }
+};
+void lstAddNonRecursiveListHandle(laListNonRecursiveRoot *root, laListHandle *newHandle, laListNonRecursiveDoFunc nrFunc, int bFreeList, void *custom_data, laListCustomDataRemover remover){
+    laListNonRecursiveItem *nrItem = CreateNew(laListNonRecursiveItem);
+
+    nrItem->bFreeList = bFreeList;
+    nrItem->func = nrFunc;
+    nrItem->CustomData = custom_data;
+    nrItem->remover = remover;
+    lstCopyHandle(&nrItem->handle, newHandle);
+
+    lstAppendItem(&root->NSItems, nrItem);
+};
+void lstCopy_NonRecursive_Root(laListHandle *FromHandle, laListHandle *ToHandle, int SizeEachNode, laListNonRecursiveCopyFunc func, void *custom_data, laListCustomDataRemover remover){
+    laListItem *li = 0, *tli = 0;
+    laListNonRecursiveRoot root = {0};
+    laListNonRecursiveItem *nrItem = CreateNew(laListNonRecursiveItem);
+    laListItem *NextLi;
+
+    nrItem->CopyFunc = func;
+    lstCopyHandle(&nrItem->handle, FromHandle);
+    nrItem->ToHandle = ToHandle; //Pointer
+    lstClearHandle(ToHandle);
+    nrItem->CustomData = custom_data;
+    nrItem->remover = remover;
+    nrItem->SizeEachNode = SizeEachNode;
+
+    lstAppendItem(&root.NSItems, nrItem);
+
+    while (lstHaveItemInList(&root.NSItems)){
+        nrItem = lstPopItem(&root.NSItems);
+        if (nrItem->CopyFunc){
+            for (li = nrItem->handle.pFirst; li; li = li->pNext){
+                tli = CreateNew_Size(nrItem->SizeEachNode);
+
+                nrItem->CopyFunc(&root, li, tli, nrItem->CustomData);
+
+                lstClearPrevNext(tli);
+                lstAppendItem(nrItem->ToHandle, tli);
+            }
+            if (nrItem->remover) nrItem->remover(nrItem->CustomData);
+        }else if (nrItem->func){
+            for (li = nrItem->handle.pFirst; li /*!=nrItem->handle.pLast*/; li = NextLi){
+                if (nrItem->func) nrItem->func(&root, li, custom_data);
+                NextLi = li->pNext;
+                if (nrItem->bFreeList){
+                    laListItem *fli = li;
+                    FreeMem(fli);
+                }
+                if (li == nrItem->handle.pLast) break;
+            }
+            if (nrItem->remover) nrItem->remover(nrItem->CustomData);
+        }
+        FreeMem(nrItem);
+    }
+};
+void lstAddNonRecursiveListCopier(laListNonRecursiveRoot *root, laListHandle *oldHandle, laListHandle *newHandle, int sizeEach, laListNonRecursiveCopyFunc nrCpyFunc, void *custom_data, laListCustomDataRemover remover){
+    laListNonRecursiveItem *nrItem = CreateNew(laListNonRecursiveItem);
+
+    nrItem->CopyFunc = nrCpyFunc;
+    lstCopyHandle(&nrItem->handle, oldHandle);
+    nrItem->ToHandle = newHandle;
+    nrItem->CustomData = custom_data;
+    nrItem->remover = remover;
+    nrItem->SizeEachNode = sizeEach;
+
+    lstAppendItem(&root->NSItems, nrItem);
+};
+
+void *lstFindItem(void *CmpData, laCompareFunc func, laListHandle *hList){
+    laListItem *it;
+
+    if (!CmpData || !hList) return 0;
+
+    it = hList->pFirst;
+    for (; it; it = it->pNext){
+        if (func(it, CmpData)) return it;
+    };
+    return 0;
+};
+void lstCombineLists(laListHandle *dest, laListHandle *src){
+    if ((!dest) || (!src)) return;
+
+    if ((!dest->pFirst) && (!dest->pLast)){
+        dest->pFirst = src->pFirst;
+        dest->pLast = src->pLast;
+    }else{
+        if (src->pLast){
+            ((laListItem *)src->pFirst)->pPrev = dest->pLast;
+            ((laListItem *)dest->pLast)->pNext = src->pFirst;
+            dest->pLast = src->pLast;
+        }
+    }
+
+    src->pFirst = 0;
+    src->pLast = 0;
+}
+void lstDestroyList(laListHandle *hlst){
+    laListItem *li, *nextli;
+    for (li = hlst->pFirst; li; li = nextli){
+        nextli = li->pNext;
+        memFree(li);
+    }
+}
+void lstDestroyListA(laListHandle *hlst){
+    laListItem *li, *nextli;
+    for (li = hlst->pFirst; li; li = nextli){
+        nextli = li->pNext;
+        FreeMem(li);
+    }
+}
+void lstDestroyList_User(laListHandle *hlst, laListDoFunc func){
+    laListItem *it = hlst->pFirst;
+    for (; it; it = it->pNext){
+        func(it);
+        FreeMem(it);
+    }
+};
+void lstCopyList(laListHandle *hOldlst, laListHandle *hNewList, int SizeEachNode, laCopyListFunc func){
+    laListItem *li, *nextli, *newli;
+    for (li = hOldlst->pFirst; li; li = nextli){
+        newli = (laListItem *)CreateNew_Size(SizeEachNode);
+        func(li, newli);
+        lstAppendItem(hNewList, newli);
+        nextli = li->pNext;
+    }
+}
+
+void *lstReMatch(laListHandle *SearchHandle, laListHandle *CurrentHandle, void *ItemToFind){
+    laListItem *sl = 0, *rl = 0;
+
+    if (!SearchHandle || !CurrentHandle || !ItemToFind) return 0;
+
+    sl = SearchHandle->pFirst;
+    rl = CurrentHandle->pFirst;
+
+    while (sl && rl){
+        if (ItemToFind == sl){
+            return rl;
+        }else{
+            sl = sl->pNext;
+            rl = rl->pNext;
+        }
+    }
+    return 0;
+}
+//void* lstReMatchEx(laListHandle* SearchHandle, laListHandle* CurrentHandle, void* ItemToFind, MatcherFunc func){
+//	laListItem* sl = 0, *rl = 0;
+//
+//	if (!SearchHandle || !CurrentHandle || !ItemToFind) return 0;
+//
+//	sl = SearchHandle->pFirst; rl = CurrentHandle->pFirst;
+//
+//	while (sl && rl){
+//		if (func(ItemToFind, sl)){
+//			return rl;
+//		}
+//		else{
+//			sl = sl->pNext;
+//			rl = rl->pNext;
+//		}
+//	}
+//	return 0;
+//}
+
+void lstAddElement(laListHandle *hlst, void *ext){
+    laElementListItem *eli = CreateNew(laElementListItem);
+    eli->Ext = ext;
+    lstAppendItem(hlst, eli);
+}
+void lstDestroyElementList(laListHandle *hlst){
+    laElementListItem *eli, *NextEli;
+    for (eli = hlst->pFirst; eli; eli = NextEli){
+        lstRemoveItem(hlst, eli);
+        NextEli = eli->Item.pNext;
+        FreeMem(eli);
+    }
+}
+
+void hsh65536Init(laHash65536** h){
+    if(!h) return; *h=calloc(1,sizeof(laHash65536));
+}
+void hshFree(laHash65536** h){
+    if(!h || !*h) return; free(*h); *h=0;
+}
+
+laListHandle* hsh65536DoHashLongPtr(laHash65536* hash, unsigned long long buckle) {
+	return &hash->Entries[(unsigned short)((buckle >> 10))];
+}
+laListHandle* hsh65536DoHashNUID(laHash65536* hash, char * NUID) {
+	u64bit Hash;
+	sscanf(NUID, "%ld", &Hash);
+	return hsh65536DoHashLongPtr(hash, (long)Hash);
+}
+laListHandle* hsh16MDoHashLongPtr(laHash16M* hash, long long buckle) {
+	return &hash->Entries[(buckle>>6)&0x00FFFFFF];
+}
+laListHandle* hsh16MDoHashNUID(laHash16M* hash, char * NUID) {
+	u64bit Hash;
+	sscanf(NUID, "%ld", &Hash);
+	return hsh65536DoHashLongPtr(hash, (long)Hash);
+}
+
+unsigned char hsh256DoHashSTR(char *buckle){
+    int i, len = 0;
+    unsigned char rev = 0;
+
+    if (buckle) len = strlen(buckle);
+
+    for (i = 0; i < len; i++){
+        rev = rev * 31 + (unsigned char)buckle[i];
+    }
+
+    return (unsigned char)rev;
+}
+
+void hsh256InsertItemCSTR(laHash256 *hash, laListItem *li, char *buckle){
+    int a = hsh256DoHashSTR(buckle);
+    lstAppendItem(&hash->Entries[a], li);
+};
+void hsh256InsertItem(laHash256 *hash, laListItem *li, char buckle){
+    lstAppendItem(&hash->Entries[(unsigned char)buckle], li);
+};
+void hsh65536InsertItem(laHash65536 *hash, laListItem *li, long buckle){
+    lstAppendItem(&hash->Entries[(unsigned short)((buckle >> 10))], li);
+    //hsh256InsertItem(&hash->HashHandles[(char)((buckle >> 8) / 8)], li, (char)(buckle/8));
+    //printf("%d %d\n", (char)(buckle >> 5), (char)(buckle >> 6));
+};
+
+laListItem *hsh256FindItemSTR(laHash256 *hash, laCompareFunc func, char *buckle){
+    unsigned char hsh;
+
+    hsh = hsh256DoHashSTR(buckle);
+
+    //if(hash->Entries[hsh].pFirst == hash->Entries[hsh].pLast)
+    //    return hash->Entries[hsh].pFirst;
+
+    return lstFindItem(buckle, func, &hash->Entries[hsh]);
+}
+
+//================================================================ [mem]
+
+void* memGetHead(void* UserMem, int* HyperLevel){
+    laMemoryPoolPart **mpp = (laMemoryPoolPart**)(((char*)UserMem)-sizeof(void*));
+    if(!(*mpp)) return 0;
+    laMemoryPool* mp = (*mpp)->PoolRoot;
+    if(HyperLevel) *HyperLevel= mp->Hyperlevel;
+    if(mp->Hyperlevel==2) return ((char*)UserMem)-sizeof(laMemNodeHyper);
+    if(mp->Hyperlevel==1) return ((char*)UserMem)-sizeof(laMemNode);
+    if(mp->Hyperlevel==0) return ((char*)UserMem)-sizeof(laMemNode0);
+    return 0;
+}
+laListHandle* memGetUserList(void* UserMem){
+    int level; void* head=memGetHead(UserMem, &level);
+    if(level==2) return &((laMemNodeHyper*)head)->Users;
+    if(level==1) return &((laMemNode*)head)->Users;
+    return 0;
+}
+laMemoryPool *memInitPool(int NodeSize, int HyperLevel){
+    if (!NodeSize) return 0;
+    laMemoryPool *mph = calloc(1, sizeof(laMemoryPool));
+    mph->NodeSize = NodeSize;
+    mph->NextCount = 1;
+    mph->Hyperlevel = HyperLevel;
+
+    u8bit Buckle = NodeSize;
+    lstAppendItem(&MAIN.GlobalMemPool.Entries[Buckle], mph);
+    return mph;
+}
+laMemoryPoolPart *memNewPoolPart(laMemoryPool *mph){
+    if (!mph->NodeSize) return 0;
+    int MemNodeSize=(mph->Hyperlevel==0)?sizeof(laMemNode0):((mph->Hyperlevel==1)?sizeof(laMemNode):sizeof(laMemNodeHyper));
+    int PoolRefOffset=MemNodeSize-sizeof(void*);
+    int RealNodeSize = mph->NodeSize + MemNodeSize;
+    int NodeCount = mph->NextCount;
+    int TotalSize = sizeof(laMemoryPoolPart) + NodeCount * RealNodeSize;
+    
+    laMemoryPoolPart *mp = calloc(1, TotalSize);
+    void *BeginMem = ((BYTE *)mp) + sizeof(laMemoryPoolPart);
+    
+    mp->PoolRoot = mph;
+    mp->FreeMemoryNodes.pFirst = mp->FreeMemoryNodes.pLast = 0;
+
+    for (int i = 0; i < NodeCount; i++){
+        void* mpn = ((BYTE *)BeginMem) + RealNodeSize * i;
+        void** ref = ((BYTE *)mpn) + PoolRefOffset;
+        (*ref)=mp;
+        lstAppendItem(&mp->FreeMemoryNodes, mpn);
+    }
+    lstPushItem(&mph->Pools, mp);
+    return mp;
+}
+void *memAcquireH(laMemoryPool *Handle){
+    laMemoryPoolPart *mp = Handle->Pools.pFirst;
+    laMemNode *mpn;
+    if (!mp || !mp->FreeMemoryNodes.pFirst){
+        mp = memNewPoolPart(Handle);
+    }
+    if (!mp) return 0;
+    mpn = mp->FreeMemoryNodes.pFirst;
+    lstRemoveItem(&mp->FreeMemoryNodes, mpn);
+    mp->UsedCount++;
+    //lstAppendItem(&mp->MemoryNodes, mpn);
+    return mpn;
+}
+void *memAcquire_(int Size, int Hyper){
+    laMemoryPool *mp;
+    u8bit Buckle = Size;
+    mp = MAIN.GlobalMemPool.Entries[Buckle].pFirst;
+    while (mp && (mp->NodeSize != Size || mp->Hyperlevel!=Hyper))
+        mp = mp->Item.pNext;
+    if (!mp) mp = memInitPool(Size, Hyper);
+    return memAcquireH(mp);
+}
+void *memAcquireSimple(int Size){
+    void *mpn = memAcquire_(Size, 0);
+    return ((char*)mpn)+sizeof(laMemNode0);
+}
+
+void *memAcquire(int Size){
+    laMemNode *mpn = memAcquire_(Size, 1);
+    void* mem = ((char*)mpn)+sizeof(laMemNode);
+    return mem;
+}
+void *memAcquireHyperNoAppend(int Size){
+    laMemNodeHyper *mpn = memAcquire_(Size, 2);
+    void* mem = ((char*)mpn)+sizeof(laMemNodeHyper);
+    memMakeHyperData(mpn);
+    return mem;
+}
+void *memAcquireHyper(int Size){
+    laMemNodeHyper *mpn = memAcquire_(Size, 2);
+    void* mem = ((char*)mpn)+sizeof(laMemNodeHyper);
+    memMakeHyperData(mpn);
+    laListHandle* l=hsh16MDoHashNUID(&MAIN.DBInst2,mpn->NUID.String);
+    lstAppendItem(l,mpn);
+    return mem;
+}
+void memFree(void *Data){
+    if (!Data) return 0;
+    int level; void* head = memGetHead(Data, &level);
+    laMemoryPoolPart *mp;
+    if(level==2) { mp = ((laMemNodeHyper*)head)->InPool; laDataBlockNoLongerExists(Data,&((laMemNodeHyper*)head)->Users);
+        laListHandle* l=hsh16MDoHashNUID(&MAIN.DBInst2,((laMemNodeHyper*)head)->NUID.String); lstRemoveItem(l,head);}
+    if(level==1) { mp = ((laMemNode*)head)->InPool; laDataBlockNoLongerExists(Data,&((laMemNode*)head)->Users); }
+    if(level==0) { mp = ((laMemNode0*)head)->InPool; }
+    laMemoryPool *mph = mp->PoolRoot;
+
+    //lstRemoveItem(&mp->MemoryNodes, head);
+    mp->UsedCount--;
+    void* head_except_item = ((char*)head)+sizeof(laListItem);
+    //memset(head_except_item, 0, ((level==2)?sizeof(laMemNodeHyper):((level==1)?sizeof(laMemNode):sizeof(laMemNode0)))+mph->NodeSize-sizeof(laListItem));
+    lstAppendItem(&mp->FreeMemoryNodes, head);
+    memset(Data, 0, mph->NodeSize);
+    MAIN.ByteCount -= mph->NodeSize;
+    if (!mp->UsedCount){
+        lstRemoveItem(&mph->Pools, mp);
+        FreeMem(mp);
+    }
+    //if (!mph->Pools.pFirst) {
+    //	mph->CountPerPool = 0;
+    //	mph->NodeSize = 0;
+    //}
+}
+void memDestroyPool(laMemoryPool *mph){
+    laMemoryPool *mp;
+    while ((mp = lstPopItem(&mph->Pools))){
+        FreeMem(mp);
+    }
+    FreeMem(mph);
+}
+
+void memNoLonger(){
+    for(int i=0;i<256;i++){
+        laMemoryPool* mp; while(mp=lstPopItem(&MAIN.GlobalMemPool.Entries[i])){ memDestroyPool(mp); }
+    }
+}
+
+laStaticMemoryPoolNode *memNewStaticPool(laStaticMemoryPool *smp){
+    laStaticMemoryPoolNode *smpn = calloc(1, LA_MEMORY_POOL_128MB);
+    smpn->UsedByte = sizeof(laStaticMemoryPoolNode);
+    lstPushItem(&smp->Pools, smpn);
+    return smpn;
+}
+void *memStaticAcquire(laStaticMemoryPool *smp, int size){
+    laStaticMemoryPoolNode *smpn = smp->Pools.pFirst;
+    void *ret;
+
+    if (!smpn || (smpn->UsedByte + size) > LA_MEMORY_POOL_128MB) smpn = memNewStaticPool(smp);
+
+    ret = ((BYTE *)smpn) + smpn->UsedByte;
+
+    smpn->UsedByte += size;
+
+    return ret;
+}
+void *memStaticAcquireThread(laStaticMemoryPool *smp, int size){
+    laStaticMemoryPoolNode *smpn = smp->Pools.pFirst;
+    void *ret;
+
+    //pthread_spin_lock(&smp->csMem);
+
+    if (!smpn || (smpn->UsedByte + size) > LA_MEMORY_POOL_128MB) smpn = memNewStaticPool(smp);
+
+    ret = ((BYTE *)smpn) + smpn->UsedByte;
+
+    smpn->UsedByte += size;
+
+    //pthread_spin_unlock(&smp->csMem);
+
+    return ret;
+}
+void *memStaticDestroy(laStaticMemoryPool *smp){
+    laStaticMemoryPoolNode *smpn;
+    void *ret;
+
+    while (smpn = lstPopItem(&smp->Pools)){
+        FreeMem(smpn);
+    }
+
+    smp->EachSize = 0;
+
+    return ret;
+}
+
+void la_ReferencedBlockDeleted(void* This, laItemUserLinker* iul){
+    void** user=iul->Pointer.p; (*user)=0;
+}
+void la_ReferrerDeleted(void* This, laItemUserLinker* iul){
+    void* instance=iul->Pointer.p; if(instance!=This){ laStopUsingDataBlock(instance, 0, This); }
+}
+void memAssignRef(void* This, void** ptr, void* instance){
+    laItemUserLinker* iul;
+    if(!This||!ptr) return;
+    if(instance){
+        laUseDataBlock(instance, 0, 0, ptr, la_ReferencedBlockDeleted, 0);
+        laUseDataBlock(This, 0, 0, instance, la_ReferrerDeleted, 0);
+    }else{
+        laStopUsingDataBlock(instance, 0, This);
+        laStopUsingDataBlock(This, 0, instance);
+    }
+    (*ptr)=instance;
+}
+void memAssignRefSafe(laSubProp* sp, void* This, void** ptr, void* instance){
+    laPropContainer* pc=sp?la_EnsureSubTarget(sp,instance):0;
+    if(pc&&!pc->OtherAlloc) memAssignRef(This,ptr,instance);
+    else (*ptr)=instance;
+}
+
+//=======================================================================[str]
+
+char *strGetNextString(char **pivot, char *NextMark){
+    int lenth = 0;
+    char *countP = *pivot;
+    char *result = 0;
+    int FloatArg = 0;
+    int i,advance;
+
+    if (**pivot == L'\0') return 0;
+
+    if (*NextMark == L'~') FloatArg = 1;
+
+    //   container@identifier=window  container#window  contianer%
+    int UC=1;
+    while (!lenth){
+        for (countP; *countP != L'.' && *(*pivot) != L'\0' && UC && *countP && *countP != L'@' && *countP != L'=' && *countP != L'#' && *countP != L'$';){
+            if((*countP)=='\\'){
+                countP++; lenth++; }
+            UC = laToUnicode(countP, &advance);
+            lenth+=advance;
+            countP+=advance;
+        }
+        if (lenth || (*countP) == 0) break;
+        (*pivot)++; countP++;
+    }
+
+    *NextMark = (*pivot)[lenth];
+    if (!(*NextMark)) *NextMark = L'.';
+
+    if (lenth){
+        result = CreateNewBuffer(char, lenth + 1);
+
+        int pi=0; for (i = 0; i < lenth; i++){
+            if((*pivot)[i]=='\\'){ continue; }
+            result[pi] = (*pivot)[i]; pi++;
+        }
+
+        result[pi] = L'\0';
+
+        if ((*pivot)[lenth] == L'\0') *pivot = &((*pivot)[lenth]);
+        else
+            (*pivot) += lenth + 1;
+
+        return result;
+    }else{
+        return 0;
+    }
+};
+int strGetStringTerminateBy(char *content, char terminator, char *Out){
+    int Ofst = 0;
+    int Skip = 0;
+    int i = 0, advance;
+
+    if ((!content) || (*content == L'\0')) return 0;
+
+    int UC;
+    for (Ofst; content[Ofst] != terminator && content[Ofst] != L'\0'; ){
+        UC = laToUnicode(&content[Ofst], &advance);
+        for(int a=0;a<advance;a++){
+            Out[i] = content[Ofst];
+            Ofst++; i++;
+        }
+    }
+    Out[i] = 0;
+
+    return i;
+};
+char *strGetNewStringTerminateBy_PivotOver(char *content, char terminator, char **NewPivot, int IgnoreSpace){
+    int Ofst = 0;
+    int Skip = 0;
+    int i = 0;
+    char *NewString;
+
+    if (!content || *content == L'\0') return 0;
+
+    if (IgnoreSpace) for (i; content[i] == L' '; i++) ;
+
+    int UC,advance;
+    for (Ofst; content[Ofst] != terminator && content[Ofst] != L'\0';){
+        UC = laToUnicode(&content[Ofst], &advance);
+        Ofst+=advance;
+    }
+
+    NewString = CreateNewBuffer(char, Ofst + 1 - i);
+
+    memcpy(NewString, &content[i], sizeof(char) * (Ofst - i));
+
+    NewString[Ofst - i] = L'\0';
+
+    *NewPivot = content[Ofst]?&content[Ofst + 1]:&content[Ofst];
+
+    return NewString;
+};
+
+int strHeadOfStringMatch(char *Str, char *SubStr){
+    int len = strlen(SubStr);
+    int i = 0;
+    for (i; i < len; i++){
+        if (Str[i] != SubStr[i]) return 0;
+    }
+    return 1;
+}
+int strSkipSegmet(char **pivot, char *content){
+    if (!pivot || !(*pivot) || !(*(*pivot)) || !content) return;
+
+    if (strHeadOfStringMatch(*pivot, content)){
+        (*pivot) += strlen(content);
+        return 1;
+    }
+    return 0;
+}
+char *strGetLastSegment(char *Content, char Seperator){
+    char *p = Content;
+    char *pn = Content;
+    while (1){
+        while (*pn != Seperator){
+            if (!(*pn)) return p;
+            pn++;
+        }
+        pn++;
+        p = pn;
+    }
+}
+void strDiscardLastSegmentSeperateBy(char *Content, char Seperator){
+    char *p = Content;
+    char *pn = Content;
+    while (1){
+        while (*pn != Seperator){
+            if (!(*pn)){
+                *p = 0;
+                return;
+            }
+            pn++;
+        }
+        p = pn;
+        pn++;
+    }
+}
+void strDiscardSameBeginningSeperatedBy(char *s1, char *s2, char **Result1, char **Result2, char Seperator){
+    int i = 0;
+    int p = 0;
+    while (s1[i] == s2[i]){
+        i++;
+        if (s1[i] == Seperator) p = i;
+        if (!s1[i]){
+            p = i;
+            break;
+        }
+        if (!s2[i]){
+            p = i;
+            break;
+        }
+    }
+    *Result1 = &s1[p];
+    *Result2 = &s2[p];
+}
+int strCountSegmentSeperateBy(char *Content, char Seperator){
+    char *p = Content;
+    char *pn = Content;
+    int c = Content[0] ? (Content[0] == Seperator ? 0 : 1) : 0;
+    while (1){
+        while (*pn != Seperator){
+            if (!(*pn)){
+                if ((*p) == Seperator) c--;
+
+                return c;
+            }
+            p = pn;
+            pn++;
+        }
+        c++;
+        pn++;
+    }
+
+    return c;
+}
+
+void strMakeDifferentName(char *Target){
+    char *p = strGetLastSegment(Target, '.');
+    int Temp;
+    if (!sscanf(p, "%d", &Temp)){
+        int l = strlen(p);
+        if (p[l - 1] != L'.') strcat(p, ".");
+        strPrintIntAfter(Target, 0, 001);
+    }else{
+        sprintf(p, "%d", Temp + 1);
+    };
+}
+
+void strReplaceCharacter(char *Str, char Find, char Replace){
+    char *p = Str;
+    if (!p) return;
+    while (*p){
+        if (*p == Find) *p = Replace;
+        p++;
+    }
+}
+void strToUpperCase(char *Str){
+    char *p = Str;
+    if (!p) return;
+    while (*p){
+        if (*p >= L'a' && *p <= L'z') *p += L'A' - L'a';
+        p++;
+    }
+}
+void strToLowerCase(char *Str){
+    char *p = Str;
+    if (!p) return;
+    while (*p){
+        if (*p >= L'A' && *p <= L'A') *p -= L'A' - L'a';
+        p++;
+    }
+}
+
+laStringSplitor *strSplitPath(char *path){
+    laStringPart *sp;
+    laStringSplitor *ss;
+    char *pivot = path;
+    char *temp_result;
+    char Type = L'.';
+    char NextType = L'.';
+
+    if (!path || !path[0]) return 0;
+
+    ss = memAcquireSimple(sizeof(laStringSplitor));
+
+    while (temp_result = strGetNextString(&pivot, &NextType)){
+        if (*temp_result != L'\0'){
+            sp = memAcquireSimple(sizeof(laStringPart));
+            sp->Content = temp_result;
+            lstAppendItem(&ss->parts, sp);
+            ss->NumberParts += 1;
+            if (NextType == L'$') sp->Type = L'$';
+            else
+                sp->Type = Type;
+            if (sp->Type == L'='){
+                if (sp->Content[0] >= L'0' && sp->Content[0] <= 9){
+                    sscanf(sp->Content, "%d", &sp->IntValue);
+                }
+            }
+            if (NextType == L'$') NextType = L'.';
+            Type = NextType;
+        }
+    }
+
+    if (ss->NumberParts == 0){
+        strDestroyStringSplitor(&ss);
+        return 0;
+    }
+
+    return ss;
+};
+
+void DF_ClearStingParts(laStringPart *sp){
+    FreeMem(sp->Content);
+};
+
+int strDestroyStringSplitor(laStringSplitor **ss){
+    if (!(*ss)) return 0;
+
+    lstForAllItemsDo(DF_ClearStingParts, &(*ss)->parts);
+    lstDestroyList(&(*ss)->parts);
+    memFree(*ss);
+    *ss = 0;
+
+    return 1;
+}
+
+char buff[128]={0};
+int strMakeInstructions(laStringSplitor **result, char *content){
+    laStringPart *sp;
+    laStringSplitor *ss = *result;
+    char *pivot = content;
+    unsigned char *temp_result;
+
+    if (!content || !content[0]) return 0;
+
+    if (!ss) ss = *result = memAcquireSimple(sizeof(laStringSplitor));
+
+    while (temp_result = strGetNewStringTerminateBy_PivotOver(pivot, '=', &pivot, 0)){
+        if (*temp_result != L'\0'){
+            sp = memAcquireSimple(sizeof(laStringPart));
+            sp->Content = temp_result;
+            lstAppendItem(&ss->parts, sp);
+            ss->NumberParts += 1;
+        }
+        temp_result = strGetNewStringTerminateBy_PivotOver(pivot, ';', &pivot, 0);
+        if (!temp_result) break;
+        if (*temp_result != L'\0'){
+            sp = memAcquireSimple(sizeof(laStringPart));
+            sp->Content = temp_result;
+            lstAppendItem(&ss->parts, sp);
+            ss->NumberParts += 1;
+            if (temp_result[0] >= L'0' && temp_result[0] <= L'9' || temp_result[0]>=128){
+                sscanf(temp_result, "%d", &sp->IntValue);
+                sscanf(temp_result, "%lf", &sp->FloatValue);
+            }
+        }
+    }
+
+    if (ss->NumberParts == 0){
+        strDestroyStringSplitor(&ss);
+        return 0;
+    }
+
+    return 1;
+}
+laStringPart *strGetArgument(laStringSplitor *ss, char *content){
+    laStringPart *sp;
+    if (!ss) return 0;
+    for (sp = ss->parts.pFirst; sp; sp = sp->Item.pNext ? ((laListItem *)sp->Item.pNext)->pNext : 0){
+        if (strSame(content, sp->Content)) return sp->Item.pNext;
+    }
+    return 0;
+}
+char *strGetArgumentString(laStringSplitor *ss, char *content){
+    laStringPart *sp;
+    if (!ss) return 0;
+    for (sp = ss->parts.pFirst; sp; sp = sp->Item.pNext ? ((laListItem *)sp->Item.pNext)->pNext : 0){
+        if (strSame(content, sp->Content)) return sp->Item.pNext ? ((laStringPart *)sp->Item.pNext)->Content : 0;
+    }
+    return 0;
+}
+int strArgumentMatch(laStringSplitor *ss, char *id, char *value){
+    laStringPart *sp;
+    if (!ss) return 0;
+    for (sp = ss->parts.pFirst; sp; sp = sp->Item.pNext ? ((laListItem *)sp->Item.pNext)->pNext : 0){
+        if (strSame(id, sp->Content)) return (strSame(((laStringPart *)sp->Item.pNext)->Content, value));
+    }
+    return 0;
+}
+int strGetIntSimple(char *content){
+    int a;
+    sscanf(content, "%d", &a);
+    return a;
+}
+real strGetFloatSimple(char *content){
+    real a;
+    sscanf(content, "%lf", &a);
+    return a;
+}
+
+void strConvInt_CString(int src, char *dest, int lenth){
+    sprintf(dest, "%d", src);
+};
+void strConvFloat_CString(real src, char *dest, int lenth){
+    sprintf(dest, "%lf", src);
+};
+
+void strCopyFull(char *dest, char *src){
+    if (src && dest) strcpy(dest, src);
+}
+void strCopySized(char *dest, int LenthLim, char *src){
+    if (src && dest) strcpy(dest, src);
+}
+
+void strPrintFloatAfter(char *dest, int LenthLim, int bits, real data){
+    char temp[64]={0};
+    sprintf(temp, "%.*lf", bits, data);
+    strcat(dest, temp);
+}
+void strPrintIntAfter(char *dest, int LenthLim, int data){
+    char temp[64]={0};
+    sprintf(&temp[0], "%d", data);
+    strcat(dest, temp);
+}
+
+void strEscapePath(char* OutCanBeSame, char* path){
+    char t[256]={0}; int ti=0;
+    for(int i=0;path[i];i++,ti++){
+        if(path[i]=='.'){ t[ti]='\\'; ti++; }
+        t[ti]=path[i];
+    }
+    strcpy(OutCanBeSame,t);
+}
+
+int strSame(char *src, char *dest){
+    return (src && dest && !strcmp(src, dest));
+}
+
+void strSafeDestroy(laSafeString **ss){
+    if (!*ss) return; lstRemoveItem(&SSC.SafeStrings, *ss);
+    if((*ss)->Ptr) memFree((*ss)->Ptr);
+    memFree(*ss); *ss=0;
+}
+void strSafeSet(laSafeString **ss, char *Content){
+    int len;
+    if (!Content||!Content[0]){ strSafeDestroy(ss); return; }
+    len = strlen(Content);
+    if (len < 1) return;
+    if (*ss){
+        char* mem=memAcquireSimple(sizeof(char)*(len+1));
+        strcpy(mem, Content);
+        memFree((*ss)->Ptr);
+        (*ss)->Ptr=mem;
+        return;
+    }
+    (*ss) = memAcquireSimple(sizeof(laSafeString));
+    (*ss)->Ptr = memAcquireSimple(sizeof(char)*(len+1));
+    strcpy((*ss)->Ptr, Content);
+    lstAppendItem(&SSC.SafeStrings, *ss);
+}
+void strSafeAppend(laSafeString **ss, char *Content){
+    if(!ss || !(*ss) || !Content){ strSafeSet(ss, Content); return; }
+    int OrigLen=strlen((*ss)->Ptr), ContentLen=strlen(Content);
+    char* mem=memAcquireSimple(sizeof(char)*(OrigLen+ContentLen+1));
+    memcpy(mem, (*ss)->Ptr, sizeof(char)*OrigLen);
+    memcpy(mem+sizeof(char)*OrigLen, Content, sizeof(char)*ContentLen);
+    mem[OrigLen+ContentLen]=0;
+    memFree((*ss)->Ptr);
+    (*ss)->Ptr=mem;
+}
+void strSafePrint(laSafeString **ss, char *Format, ...){
+    char content[512]; va_list va; va_start(va, Format); vsprintf(content, Format, va); va_end(va);
+    strSafeAppend(ss,content);
+}
+void strSafePrintV(laSafeString **ss, char *Format, va_list args){
+    char content[512]; va_list va; vsprintf(content, Format, args);
+    strSafeAppend(ss,content);
+}
+
+void strSafeDump(){
+    laSafeString*ss;
+    while(ss=lstPopItem(&SSC.SafeStrings)){
+        if(ss->Ptr) printf("[String not freed] \"%s\"\n", ss->Ptr);
+    }
+}
+
+void strBeginEdit(laStringEdit **se, char *FullStr){
+    char *p = FullStr;
+    char buf[1024];
+    laStringEdit *nse = CreateNew(laStringEdit);
+    if(*se){ memcpy(nse,*se,sizeof(laStringEdit)); nse->Lines.pFirst=nse->Lines.pLast=0; nse->TotalLines=0; }
+    strEndEdit(se, 1);
+    nse->_BeginLine = -1; nse->_BeginBefore = -1;
+    if (FullStr && FullStr[0]){
+        while ((*p)){
+            laStringLine *sl = memAcquireSimple(sizeof(laStringLine));
+            p += strGetStringTerminateBy(p, '\n', buf);
+            strToUnicode(sl->Buf, buf);
+            lstAppendItem(&nse->Lines, sl); nse->TotalLines++;
+            if(*p){ p+=1; }
+        }
+    }
+    if (!nse->Lines.pFirst){
+        laStringLine *sl = memAcquireSimple(sizeof(laStringLine));
+        lstAppendItem(&nse->Lines, sl); nse->TotalLines++;
+    }
+    *se=nse;
+}
+char* strGetEditString(laStringEdit *se, int SelectionOnly){
+    if(!se) return 0; char* result=0; int next=0, max=0, len=0;
+    arrEnsureLength(&result, 0, &max, sizeof(char)); int NextChar=0;
+    int Line=0, starti=0, endat=0;
+    for(laStringLine* sl=se->Lines.pFirst;sl;sl=sl->Item.pNext,Line++){
+        starti=0;
+        if(SelectionOnly && Line<se->BeginLine){ continue; }
+        if(SelectionOnly && Line==se->BeginLine){ starti=se->BeginBefore; }
+        int tlen=strlenU(&sl->Buf[starti]); int Extra=sl->Item.pNext?2:1;
+        arrEnsureLength(&result, (len+tlen)*4+Extra, &max, sizeof(char));
+        if(SelectionOnly && Line==se->EndLine){ endat=NextChar+se->EndBefore-starti; }
+        NextChar+=strToUTF8(&result[NextChar], &sl->Buf[starti]); len+=tlen;
+        if(Extra==2){ result[NextChar]='\n'; NextChar+=1; }
+        if(SelectionOnly && Line==se->EndLine){ result[endat]=0; break; }
+    }
+    return result;
+}
+char* strEndEdit(laStringEdit **se, int FreeString){
+    char *p=0; laStringLine *sl, *NextSl;
+    if (!se || !(*se)) return 0;
+    p=strGetEditString(*se, 0);
+    while (sl=lstPopItem(&(*se)->Lines)){ memFree(sl); }
+    FreeMem(*se); *se=0;
+    if(FreeString && p){ free(p); p=0; }
+    return p;
+}
+void strSetEditViewRange(laStringEdit* se, int Lines, int Cols){
+    se->ViewHeight = Lines; se->ViewWidth = Cols;
+}
+void strEnsureCursorVisible(laStringEdit* se){
+    if(!se->ViewHeight || !se->ViewWidth || se->CursorLine<0 || se->CursorBefore<0 ){return;}
+    if(se->CursorLine>se->ViewHeight+se->ViewStartLine-1){ se->ViewStartLine=se->CursorLine-se->ViewHeight+1; }
+    if(se->CursorLine<se->ViewStartLine){ se->ViewStartLine=se->CursorLine; }
+    if(se->CursorBefore>se->ViewStartCol+se->ViewWidth-1){ se->ViewStartCol=se->CursorBefore-se->ViewWidth+1; }
+    if(se->CursorBefore<se->ViewStartCol){ se->ViewStartCol=se->CursorBefore; }
+}
+void strRemoveLine(laStringEdit *se, laStringLine *sl){
+    lstRemoveItem(&se->Lines, sl);
+    memFree(sl); se->TotalLines--;
+}
+void strRemoveLineI(laStringEdit *se, int LineIndex){
+    int i = 0;
+    laStringLine *sl = se->Lines.pFirst, *NextSl;
+    while (sl){
+        NextSl = sl->Item.pNext;
+        if (i == LineIndex){ strRemoveLine(se, sl); break; }
+        i++;
+        sl = NextSl;
+    }
+}
+void strSetCursor(laStringEdit *se, int LineIndex, int BeforeIndex){
+    int maxbefore;
+    if (!se) return;
+    
+    if(LineIndex<0){LineIndex=0;}
+    se->CursorLine = LineIndex;
+
+    maxbefore = strlenU(strGetCursorLine(se, &se->CursorLine)->Buf);
+
+    BeforeIndex = BeforeIndex < 0 ? 0 : BeforeIndex > maxbefore ? maxbefore : BeforeIndex;
+
+    se->CursorBefore = BeforeIndex;
+    se->BeginLine = -1;
+    se->BeginBefore = -1;
+    se->EndLine = -1;
+    se->EndBefore = -1;
+
+    strEnsureCursorVisible(se);
+}
+void strMoveCursor(laStringEdit *se, int Left, int Select){
+    int maxbefore;
+    int BeforeIndex;
+    int width = 1;
+    laStringLine *sl;
+    if (!se) return;
+
+    if(Select){ strLazySelect(se); } else { strCancelSelect(se); }
+
+    sl = strGetCursorLine(se, 0);
+    maxbefore = strlenU(sl->Buf);
+
+    BeforeIndex = se->CursorBefore - (Left ? 1 : -1);
+
+    if(BeforeIndex<0){
+        strSetCursor(se, se->CursorLine-1, INT_MAX);
+    }elif(BeforeIndex>maxbefore && se->CursorLine<se->TotalLines-1){
+        strSetCursor(se, se->CursorLine+1, 0);
+    }else{
+        se->CursorBefore = BeforeIndex>=maxbefore?maxbefore:BeforeIndex;
+    }
+
+    se->CursorPreferBefore = se->CursorBefore;
+
+    se->BeginLine = -1;
+    se->BeginBefore = -1;
+    se->EndLine = -1;
+    se->EndBefore = -1;
+
+    if(Select){ strEndSelect(se); }
+
+    strEnsureCursorVisible(se);
+}
+void strMoveCursorLine(laStringEdit *se, int Up, int Select){
+    int Line, maxbefore, LastIndex=-1;
+    laStringLine *sl;
+    if (!se) return;
+
+    if(Select){ strLazySelect(se); } else { strCancelSelect(se); }
+
+    Line=se->CursorLine - (Up? 1:-1);
+    if(Line<0) {Line=0;}
+    se->CursorLine = Line;
+
+    sl = strGetCursorLine(se, &LastIndex);
+
+    if(LastIndex>=0){ se->CursorLine = LastIndex; se->CursorPreferBefore=10000; }
+    maxbefore = strlenU(sl->Buf);
+    se->CursorBefore = se->CursorPreferBefore;
+    if(se->CursorBefore>maxbefore){ se->CursorBefore = maxbefore; }
+    if(LastIndex>=0){se->CursorPreferBefore=se->CursorBefore;}
+
+    if(Select){ strEndSelect(se); }
+
+    strEnsureCursorVisible(se);
+}
+int strHasSelection(laStringEdit* se){
+    return se->BeginBefore!=se->EndBefore||se->BeginLine!=se->EndLine;
+}
+void strCancelSelect(laStringEdit *se){
+    if (!se) return;
+    se->_BeginLine = -1;
+    se->_BeginBefore = -1;
+    se->BeginLine = -1;
+    se->EndLine = -1;
+    se->BeginBefore = -1;
+    se->EndBefore = -1;
+}
+void strLazySelect(laStringEdit *se){
+    if (!se || se->_BeginLine>=0) return;
+    se->_BeginLine = se->CursorLine;
+    se->_BeginBefore = se->CursorBefore;
+}
+void strEndSelect(laStringEdit *se){
+    if (!se) return;
+    se->_EndLine = se->CursorLine;
+    se->_EndBefore = se->CursorBefore;
+    se->BeginLine =   se->_BeginLine;
+    se->EndLine =     se->_EndLine;
+    se->BeginBefore = se->_BeginBefore;
+    se->EndBefore =   se->_EndBefore;
+    if(se->BeginLine>se->EndLine || (se->BeginLine==se->EndLine && se->BeginBefore>se->EndBefore))
+        { LA_SWAP(int,se->BeginLine,se->EndLine); LA_SWAP(int,se->BeginBefore,se->EndBefore); }
+}
+void strSelectLineAll(laStringEdit *se){
+    if (!se) return;
+    laStringLine *sl;
+    int len;
+    if (se->CursorLine == -1) sl = strGetBeginLine(se);
+    else
+        sl = strGetCursorLine(se, 0);
+    len = strlenU(sl->Buf);
+
+    se->EndBefore = len; se->EndLine=0;
+    se->BeginBefore = 0; se->BeginLine=0;
+
+    se->CursorBefore = len;
+    se->CursorLine = 0;
+}
+void strDeselectAll(laStringEdit *se){
+    if (!se) return;
+    laStringLine *sl;
+    int len;
+    if (se->CursorLine == -1) sl = strGetBeginLine(se);
+    else
+        sl = strGetCursorLine(se, 0);
+    len = strlenU(sl->Buf);
+
+    se->EndBefore = -1;
+    se->BeginBefore = -1;
+    se->BeginLine = -1;
+    se->EndLine = -1;
+
+    se->CursorBefore = len;
+    se->CursorLine = -1;
+}
+void strPanFoward(uint32_t *str, int Before, int Offset){
+    int len = strlenU(str);
+    int i = len + 1;
+    for (i; i >= Before; i--){
+        str[i + Offset] = str[i];
+    }
+}
+void strSquishBackward(uint32_t *str, int Before, int EndBefore){
+    int len = strlenU(str);
+    int i = Before;
+    int Offset = Before - EndBefore;
+    if (Before <= 0) return;
+    for (i; i <= len; i++){
+        str[i - Offset] = str[i];
+    }
+}
+void strClearSelection(laStringEdit *se){
+    //if (se->EndLine == -1) return;
+    if (se->BeginLine != se->EndLine){
+        int i = 0; int RemovedLines=0;
+        laStringLine *sl = se->Lines.pFirst, *NextSl;
+        while (sl){
+            NextSl = sl->Item.pNext;
+            if (i == se->BeginLine){
+                sl->Buf[se->BeginBefore] = L'\0';
+            }else if (i > se->BeginLine && i < se->EndLine){
+                strRemoveLine(se, sl); RemovedLines++;
+            }else if (i == se->EndLine){
+                strSquishBackward(sl->Buf, se->EndBefore, 0);
+                se->CursorLine = i-RemovedLines;
+                se->CursorBefore = 0;
+                se->BeginLine = -1;
+                se->BeginBefore = -1;
+                se->EndLine = -1;
+                se->EndBefore = -1;
+                strBackspace(se);
+            }
+            if (i > se->EndLine) break;
+            i++;
+            sl = NextSl;
+        }
+    }else{
+        int i = 0;
+        laStringLine *sl = se->Lines.pFirst, *NextSl;
+        while (sl){
+            NextSl = sl->Item.pNext;
+            if (i == se->EndLine) {
+                strSquishBackward(sl->Buf, se->EndBefore, se->BeginBefore);
+                se->CursorLine = i;
+                se->CursorBefore = se->BeginBefore;
+                se->BeginLine = -1;
+                se->BeginBefore = -1;
+                se->EndLine = -1;
+                se->EndBefore = -1;
+                break;
+            }
+            i++; sl = NextSl;
+        }
+    }
+    strEnsureCursorVisible(se);
+}
+laStringLine *strGetCursorLine(laStringEdit *se, int* ReturnIndexIfLast){
+    if (!se || se->CursorBefore <= -1) return se->Lines.pFirst;
+    int i = 0;
+    laStringLine *sl = se->Lines.pFirst, *NextSl;
+    while (sl){
+        NextSl = sl->Item.pNext;
+        if (i == se->CursorLine){
+            return sl;
+        }
+        i++;
+        sl = NextSl;
+    }
+    if(ReturnIndexIfLast){ *ReturnIndexIfLast=i-1;}
+    return se->Lines.pLast;
+}
+laStringLine *strGetBeginLine(laStringEdit *se){
+    if (!se || se->BeginLine <= -1) return se->Lines.pFirst;
+    int i = 0;
+    laStringLine *sl = se->Lines.pFirst, *NextSl;
+    while (sl){
+        NextSl = sl->Item.pNext;
+        if (i == se->BeginLine){
+            return sl;
+        }
+        i++;
+        sl = NextSl;
+    }
+    return se->Lines.pFirst;
+}
+void strInsertChar(laStringEdit *se, uint32_t a){
+    laStringLine *sl;
+    strClearSelection(se);
+    sl = strGetCursorLine(se, 0);
+    if(a==L'\n'){
+        laStringLine* nl=memAcquireSimple(sizeof(laStringLine));
+        if(sl->Buf[se->CursorBefore]!=L'\0') strcpyU(nl->Buf, &sl->Buf[se->CursorBefore]);
+        sl->Buf[se->CursorBefore]=L'\0';
+        se->CursorLine++; se->CursorBefore=0;
+        lstInsertItemAfter(&se->Lines, nl, sl); se->TotalLines++;
+    }else{
+        strPanFoward(sl->Buf, se->CursorBefore, 1);
+        sl->Buf[se->CursorBefore] = a;
+        se->CursorBefore += 1;
+    }
+    se->CursorPreferBefore = se->CursorBefore;
+    strEnsureCursorVisible(se);
+}
+void strBackspace(laStringEdit *se){
+    laStringLine *sl;
+    int width = 1;
+    if (se->CursorBefore == -1){
+        strClearSelection(se);
+    }else{
+        laStringLine *sl;
+        sl = strGetCursorLine(se, 0);
+        if (se->CursorBefore > 1 && sl->Buf[se->CursorBefore - 2] < 0) width = 2;
+        strSquishBackward(sl->Buf, se->CursorBefore, se->CursorBefore - width);
+        se->CursorBefore -= width;
+        if (se->CursorBefore <= -1){
+            if(sl->Item.pPrev){
+                laStringLine* ol=sl->Item.pPrev;
+                se->CursorBefore = strlenU(ol->Buf);
+                se->CursorLine--;
+                strcatU(ol->Buf, sl->Buf);
+                strRemoveLine(se, sl);
+            }
+            else {se->CursorBefore = 0;}
+        }
+    }
+    se->CursorPreferBefore = se->CursorBefore;
+    strEnsureCursorVisible(se);
+}
+void strMoveView(laStringEdit *se, int DownLines, int RightCharacters){
+    se->ViewStartLine+=DownLines;
+    se->ViewStartCol+=RightCharacters;
+    if(se->ViewStartLine>=se->TotalLines-1) se->ViewStartLine=se->TotalLines-1;
+    if(se->ViewStartLine<0) se->ViewStartLine=0;
+    if(se->ViewStartCol<0) se->ViewStartCol=0;
+}
+
+//======================================================[ translation ]
+
+void transNewLanguage(const char *LanguageID){
+    laTranslationNode *tn = CreateNew(laTranslationNode);
+    strSafeSet(&tn->LanguageName, LanguageID);
+
+    lstAppendItem(&MAIN.Translation.Languages, tn);
+
+    MAIN.Translation.CurrentLanguage = tn;
+}
+void transSetLanguage(const char *LanguageID){
+    laTranslationNode *tn;
+
+    if (!LanguageID){
+        MAIN.Translation.CurrentLanguage = 0;
+        return;
+    }
+
+    for (tn = MAIN.Translation.Languages.pFirst; tn; tn = tn->Item.pNext){
+        if (!strcmp(tn->LanguageName->Ptr, LanguageID)){
+            MAIN.Translation.CurrentLanguage = tn;
+            break;
+        }
+    }
+}
+void transDumpMissMatchRecord(const char *filename){
+    laTranslationMatch *tm;
+    laListHandle *lst;
+    int i;
+
+    FILE *f = fopen(filename, "w");
+    if (!f) return;
+
+    for (i = 0; i < 256; i++){
+        lst = &MAIN.Translation.MisMatches.Entries[i];
+        for (tm = lst->pFirst; tm; tm = tm->Item.pNext){
+            fprintf(f, "transNewEntry(\"%s\",\"\");\n", tm->Target);
+        }
+    }
+
+    fclose(f);
+}
+int IsThisTranslationMatch(laTranslationMatch *tm, char *p){
+    return (tm->Target && !strcmp(tm->Target, p));
+}
+void transNewEntry(const char *Target, const char *replacement){
+    laTranslationMatch *tm = memAcquireSimple(sizeof(laTranslationMatch));
+    tm->Target = Target;
+    tm->Replacement = replacement;
+    hsh256InsertItemCSTR(&MAIN.Translation.CurrentLanguage->Matches, tm, Target);
+}
+void transNewMissEntry(const char *Target){
+    if (!hsh256FindItemSTR(&MAIN.Translation.MisMatches, IsThisTranslationMatch, Target)){
+        laTranslationMatch *tm = memAcquireSimple(sizeof(laTranslationMatch));
+        tm->Target = Target;
+        hsh256InsertItemCSTR(&MAIN.Translation.MisMatches, tm, Target);
+    }
+}
+char *transLate(char *Target){
+    if (!MAIN.Translation.CurrentLanguage || !MAIN.Translation.EnableTranslation) return Target;
+    laTranslationMatch *tm = hsh256FindItemSTR(&MAIN.Translation.CurrentLanguage->Matches, IsThisTranslationMatch, Target);
+    if (!tm){
+        transNewMissEntry(Target);
+        return Target;
+    }
+    return tm->Replacement;
+}
+void transState(void *UNUSED, int val){
+    if (val) MAIN.Translation.EnableTranslation = 1;
+    else
+        MAIN.Translation.EnableTranslation = 0;
+
+    laRedrawCurrentWindow();
+}
+
+//=========================================================[ Internet ]
+
+void laOpenInternetLink(char *link){
+    //HKEY hkRoot, hSubKey;
+    //char ValueName[256]={0};
+    //char DataValue[256]={0};
+    //unsigned long cbValueName = 256;
+    //unsigned long cbDataValue = 256;
+    //char ShellChar[512]={0};
+    //DWORD dwType;
+//
+    //ShellExecute(0, "open", link, 0, 0, SW_SHOWNORMAL);
+//
+    //return;
+}
+
+//===========================================================[ deprecated ]
+
+void laSendPanic(char *message){
+    printf("Panic: %s\n",message);
+    exit(0);
+}
+
+//===========================================================[ file util ]
+
+char *txtReadFileAsString(char *FileName){
+    FILE *f = fopen(FileName, "r");
+    int length;
+    fseek(f, 0, SEEK_END);
+    length = ftell(f);
+    fseek(f, 0, SEEK_SET);
+
+    char *buffer = CreateNewBuffer(char, length);
+
+    fread(buffer, sizeof(char), length, f);
+
+    fclose(f);
+
+    return buffer;
+}

+ 619 - 0
source/lagui/la_util.h

@@ -0,0 +1,619 @@
+#pragma once
+
+/*
+NUL4.0 - Nick's Best - www.nicksbest.com
+Author(s):WuYiming - xp8110@outlook.com
+
+Want to join the development?
+Append your name in the authors list above.
+Send feedback to la_support@nicksbest.com
+*/
+
+#define _CRT_SECURE_NO_WARNINGS
+
+
+#include "GL/glew.h"
+
+#include "GL/gl.h"
+#include "ft2build.h"
+#include "freetype/freetype.h"
+#include "la_icon.h"
+#include "pthread.h"
+#include <wchar.h>
+
+#define NEED_STRUCTURE(a)\
+typedef struct _##a a;
+
+#define STRUCTURE(a)\
+typedef struct _##a a;\
+struct _##a
+
+#define lengthof(a)\
+(sizeof(a)/sizeof(a[0]))
+
+#define DBL_TRIANGLE_LIM 1e-11
+#define DBL_EDGE_LIM 1e-9
+
+
+#define LA_HYPER_CREATED_TIME(hi)\
+hi->TimeCreated.Year,hi->TimeCreated.Month,hi->TimeCreated.Day,hi->TimeCreated.Hour,hi->TimeCreated.Minute,hi->TimeCreated.Second
+
+
+typedef double real;
+typedef unsigned long long u64bit;
+typedef unsigned int       u32bit;
+typedef unsigned short     u16bit;
+typedef unsigned short     ushort;
+typedef unsigned char      u8bit;
+
+typedef struct _laListSingle laListSingle;
+struct _laListSingle {
+	void* pNext;
+};
+
+typedef struct _laListHandle laListHandle;
+struct _laListHandle {
+	void* pFirst;
+	void* pLast;
+};
+
+typedef struct _laListWithPivot laListWithPivot;
+struct _laListWithPivot {
+	void* pFirst;
+	void* pLast;
+	void* Pivot;
+};
+
+typedef struct _laListItem laListItem;
+struct _laListItem {
+	void* pPrev;
+	void* pNext;
+};
+
+typedef struct _laListItem2 laListItem2;
+struct _laListItem2 {
+	void* O1;
+	void* O2;
+	void* pPrev;
+	void* pNext;
+};
+
+typedef struct _laListItem3 laListItem3;
+struct _laListItem3 {
+	void* O1;
+	void* O2;
+	void* O3;
+	void* O4;
+	void* pPrev;
+	void* pNext;
+};
+
+
+NEED_STRUCTURE(laSafeString);
+STRUCTURE(laAuthorInfo) {
+	laListItem    Item;
+	laSafeString* Name;
+	laSafeString* CopyrightString;
+};
+STRUCTURE(laTimeInfo) {
+	u16bit Year;//Also Used As Timer [ms] counter
+	u8bit  Month;
+	u8bit  Day;
+	u8bit  Hour;
+	u8bit  Minute;
+	u8bit  Second;
+};
+
+NEED_STRUCTURE(laPropContainer);
+
+typedef struct _laUID laUID;
+struct _laUID {
+	char String[32];//a simplified uuid, example: 0E3F9BA4802FDDC2-20160601123546 [\0]
+};
+
+typedef struct _laListItemPointer laListItemPointer;
+struct _laListItemPointer {
+	void* pPrev;
+	void* pNext;
+	void* p;
+};
+
+typedef struct _laItemUserLinker laItemUserLinker;
+typedef void(*laUserRemoveFunc)(void* This, laItemUserLinker* iul);
+NEED_STRUCTURE(laProp);
+struct _laItemUserLinker {
+	laListItemPointer Pointer;
+	laUserRemoveFunc  Remove;
+	laProp*           Which;
+	unsigned int      FrameDistinguish;
+	int               ForceRecalc;
+};
+typedef struct _laItemUserLinkerLocal laItemUserLinkerLocal;
+struct _laItemUserLinkerLocal {
+	laItemUserLinker Link;
+	void*            Instance;
+};
+
+
+typedef struct _laElementListItem laElementListItem;
+struct _laElementListItem {
+	laListItem Item;
+	void*     Ext;
+};
+
+typedef struct _laListNonRecursiveRoot laListNonRecursiveRoot;
+struct _laListNonRecursiveRoot {
+	laListHandle NSItems;
+};
+
+typedef int(*laCompareFunc)(void*, void*);
+typedef void(*laListDoFunc)(void*);
+typedef void(*laListNonRecursiveDoFunc)(laListNonRecursiveRoot*, void*, void*);//item,custom
+typedef void(*laListNonRecursiveCopyFunc)(laListNonRecursiveRoot*, void*, void*, void*);//old,new,custom
+typedef void(*laListDoFuncArgp)(void*, void*);
+typedef void(*laCopyListFunc)(void*, void*);
+typedef void(*laListCustomDataRemover)(void*);
+//typedef void(*ListMatcherFunc)(void*,void*);//gotten value,enumed curent lst item.
+
+typedef struct _laListNonRecursiveItem laListNonRecursiveItem;
+struct _laListNonRecursiveItem {
+	laListItem               Item;
+	laListHandle             handle;
+	laListHandle            *ToHandle;//This Is Pointer!
+	laListNonRecursiveDoFunc func;
+	laListNonRecursiveCopyFunc CopyFunc;
+	laListCustomDataRemover    remover;
+	void*                  CustomData;
+	int                    bFreeList;
+	int                    SizeEachNode;
+};
+
+
+typedef struct _laHash256 laHash256;
+struct _laHash256 {
+	laListHandle Entries[256];
+};
+
+typedef struct _laHash65536 laHash65536;
+struct _laHash65536 {
+	laListHandle Entries[65536];
+	//laHash256 HashHandles[256];
+};
+
+typedef struct _laHash16M laHash16M;
+struct _laHash16M {
+	laListHandle Entries[16777216];
+};
+
+typedef struct _laSafeString laSafeString;
+struct _laSafeString {
+	laListItem Item;
+	char *     Ptr;
+};
+
+typedef struct _laSafeStringCollection laSafeStringCollection;
+struct _laSafeStringCollection {
+	laListHandle SafeStrings;
+};
+
+typedef struct _laStringSplitor laStringSplitor;
+struct _laStringSplitor {
+	int         NumberParts;
+	laListHandle parts;
+};
+
+typedef struct _laStringPart laStringPart;
+struct _laStringPart {
+	laListItem  Item;
+	char *      Content;
+	int        IntValue;
+	real      FloatValue;
+	char       Type;
+};
+
+STRUCTURE(laStringLine) {
+	laListItem Item;
+	wchar_t   Buf[1024];//unicode
+};
+
+STRUCTURE(laStringEdit) {
+	laListHandle Lines;
+	int CursorLine, CursorBefore, CursorPreferBefore;
+	int BeginLine, BeginBefore;
+	int EndLine,   EndBefore;
+	int _BeginLine, _BeginBefore; // selection order
+	int _EndLine,   _EndBefore;
+	int TotalLines;
+	int ViewStartLine, ViewStartCol;
+	int ViewHeight, ViewWidth;
+	int MouseSelecting;
+};
+
+#define LA_SWAP(T,x,y)\
+	{ T SWAP = x; x = y; y = SWAP; }
+
+#define LA_MEMORY_POOL_1MB   1048576
+#define LA_MEMORY_POOL_128MB 134217728
+#define LA_MEMORY_POOL_256MB 268435456
+#define LA_MEMORY_POOL_512MB 536870912
+
+STRUCTURE(laMemoryPool) {
+	laListItem   Item;
+	int          NodeSize;
+	int          NextCount;
+	int          UsableCount;
+	int          Hyperlevel;
+	laListHandle Pools;
+};
+
+STRUCTURE(laMemoryPoolPart) {
+	laListItem   Item;
+	laListHandle FreeMemoryNodes;
+	int UsedCount;
+	laMemoryPool* PoolRoot;
+	//<------Pool mem starts here
+};
+
+NEED_STRUCTURE(laDBInst);
+
+STRUCTURE(laMemNode0){
+	laListItem        Item;
+	laMemoryPoolPart* InPool;//<---- Keep at the last
+	//<------User mem starts here
+};
+
+STRUCTURE(laMemNode) {
+	laListItem        Item;
+	laListHandle      Users;  //<---- Keep at the second
+	void*             ReadInstance;
+	laMemoryPoolPart* InPool; //<---- Keep at the last
+	//<------User mem starts here
+};
+
+NEED_STRUCTURE(laManagedUDF);
+STRUCTURE(laMemNodeHyper) {
+	laListItem        Item;
+	laListHandle      Users;  //<---- Keep at the second
+	laUID             NUID;
+	laTimeInfo        TimeCreated;
+	laManagedUDF*     FromFile;
+	int               Modified;
+	int               UNUSEDUndoDirty;
+	laMemoryPoolPart* InPool; //<---- Keep at the last
+	//<------User mem starts here
+};
+
+STRUCTURE(laStaticMemoryPoolNode) {
+	laListItem Item;
+	int       UsedByte;
+	//<------User mem starts here
+};
+
+STRUCTURE(laStaticMemoryPool) {
+	int         EachSize;
+	laListHandle Pools;
+	//pthread_spinlock_t csMem;
+};
+
+
+
+STRUCTURE(laAVLNodeReal64) {
+	laAVLNodeReal64* Parent;
+	u64bit          Index;
+	real            Value;
+	//real            SmallestValue;
+	//real            GreatestValue;
+	laAVLNodeReal64* Smaller;
+	laAVLNodeReal64* Greater;
+	char            Height;
+	void*           Pointer;
+};	
+
+STRUCTURE(laAVLTreeReal64) {
+	laAVLNodeReal64*   Root;
+	u64bit            ItemCount;
+	laMemoryPool       MemoryPool;
+};
+
+
+STRUCTURE(laTimeRecorder) {
+	//SYSTEMTIME Time;
+	time_t     At;
+};
+
+STRUCTURE(laTranslationNode) {
+	laListItem    Item;
+	laSafeString* LanguageName;
+	laHash256     Matches;
+};
+
+STRUCTURE(laTranslation) {
+	int                EnableTranslation;
+	laListHandle       Languages;
+	laTranslationNode* CurrentLanguage;
+	laHash256          MisMatches;
+};
+
+STRUCTURE(laTranslationMatch) {
+	laListItem Item;
+	char * Target;
+	char * Replacement;
+};
+
+
+char * txtReadFileAsString(char * FileName);
+
+
+void laSendPanic(char * message);
+
+#define SEND_PANIC_ERROR(message)\
+    laSendPanic(message)
+
+#define SEND_NORMAL_ERROR(message)
+
+#define SEND_USER_MESSAGE(message)                                                
+    //MessageBox(0,message, "Message here:",0)
+
+#define CreateNew(Type)\
+    calloc(sizeof(Type),1)
+
+
+#define CreateNew_Size(size)\
+    calloc(size,1)
+
+#define CreateNewBuffer(Type,Num)\
+    calloc(sizeof(Type),Num);
+
+#define FreeMem(ptr)\
+    nutFreeMem((&ptr))
+
+#define elif\
+        else if
+
+#define LA_UNAVAILABLE_NAME "- Unknown -"
+
+uint32_t laToUnicode(const unsigned char* ch, int* advance);
+int laToUTF8(const uint32_t ch, char* out, char** next);
+int strToUnicode(uint32_t* target, unsigned char* const src);
+int strToUTF8(unsigned char* target, uint32_t* const src);
+int strlenU(uint32_t* const str);
+int strcpyU(uint32_t* target, uint32_t* const source );
+int strcatU(uint32_t* target, uint32_t* const source );
+
+struct tm* laGetFullTime();
+
+void laRecordTime(laTimeRecorder* tr);
+real laTimeElapsedSecondsf(laTimeRecorder* End, laTimeRecorder* Begin);
+int laTimeElapsedMilliseconds(laTimeRecorder* End, laTimeRecorder* Begin);
+
+void laSetAuthorInfo(char * Name, char * CopyrightString);
+
+void memCreateNUID(laMemNodeHyper* hi);
+
+NEED_STRUCTURE(laPropPack);
+
+int nutHyperUserCount(void* instance, laProp* p_optional, int *p_count);
+void memHyperInfo(laPropPack* pp, char* buf);
+void memMakeHyperData(laMemNodeHyper* hi);
+void nutFreeMem(void** ptr);
+int nutFloatCompare(real l, real r);
+
+int nutSameAddress(void* l, void* r);
+
+void* arrElement(void* head, int i, int size);
+int arrEnsureLength(void** head, int next, int* max, size_t ElementSize);
+int arrInitLength(void** head, int max, int* pmax, size_t ElementSize);
+void arrFree(void** head, int* max);
+
+void lstPushSingle(void** Head, laListSingle* Item);
+void* lstPopSingle(void** Head, laListSingle* Item);
+
+void lstClearPrevNext(laListItem* li);
+int lstCountElements(laListHandle* Handle);
+void lstAppendItem(laListHandle* Handle, void* Item);
+void lstPushItem(laListHandle* Handle, void* Item);
+void* lstPopItem(laListHandle* Handle) ;
+
+void  lstAppendItem2(laListHandle* Handle, void* Item);
+void* lstPopItem2(laListHandle* Handle);
+void  lstPushItem2(laListHandle* Handle, void* Item);
+void  lstAppendItem3(laListHandle* Handle, void* Item);
+void* lstPopItem3(laListHandle* Handle);
+void  lstPushItem3(laListHandle* Handle, void* Item);
+
+int lstRemoveItem(laListHandle* Handle, laListItem* li) ;
+int lstRemoveItem2(laListHandle* Handle, laListItem2* li);
+
+int lstRemoveSegment(laListHandle* Handle, laListItem* Begin, laListItem* End);
+void lstInsertItemBefore(laListHandle* Handle, laListItem* toIns, laListItem* pivot);
+void lstInsertItemAfter(laListHandle* Handle, laListItem* toIns, laListItem* pivot);
+void lstInsertSegmentBefore(laListHandle* Handle, laListItem* Begin, laListItem* End, laListItem* pivot);
+void lstInsertSegmentAfter(laListHandle* Handle, laListItem* Begin, laListItem* End, laListItem* pivot);
+int   lstHaveItemInList(laListHandle* Handle);
+/**/ void* lstGetTop(laListHandle* Handle);
+
+void lstPushSimpleItem(void** first, laItemUserLinker* iul);
+void* lstPushItemUser(void** first, void* p);
+void* lstPushItemUsing(void** first, void* p);
+
+void* lstAppendPointerOnly(laListHandle* h, void* p);
+void* lstAppendPointerSizedOnly(laListHandle* h, void* p, int size);
+void* lstPushPointerOnly(laListHandle* h, void* p);
+void* lstPushPointerSizedOnly(laListHandle* h, void* p, int size);
+
+int lstHasPointer(laListHandle* h, void *p);
+void* lstAppendPointer(laListHandle* h, void* p);
+void* lstAppendPointerSized(laListHandle* h, void* p, int size);
+void* lstPushPointer(laListHandle* h, void* p);
+void* lstPushPointerSized(laListHandle* h, void* p, int size);
+
+void* lstAppendPointerStatic(laListHandle* h, laStaticMemoryPool* smp, void* p);
+void* lstAppendPointerStaticSized(laListHandle* h, laStaticMemoryPool* smp, void* p, int size);
+void* lstPushPointerStatic(laListHandle* h, laStaticMemoryPool* smp, void* p);
+void* lstPushPointerStaticSized(laListHandle* h, laStaticMemoryPool* smp, void* p, int size);
+
+void* lstPopPointerOnly(laListHandle* h);
+void lstRemovePointerItemOnly(laListHandle* h, laListItemPointer* lip);
+void lstRemovePointerOnly(laListHandle* h, void* p);
+void lstClearPointerOnly(laListHandle* h);
+void lstGeneratePointerListOnly(laListHandle* from1, laListHandle* from2, laListHandle* to);
+
+void* lstPopPointer(laListHandle* h);
+void lstRemovePointerItem(laListHandle* h, laListItemPointer* lip);
+void lstRemovePointer(laListHandle* h, void* p);
+void lstRemovePointerLeave(laListHandle *h, void *p);
+void lstClearPointer(laListHandle* h);
+void lstGeneratePointerList(laListHandle* from1, laListHandle* from2, laListHandle* to);
+
+void lstCopyHandle(laListHandle* target, laListHandle* src);
+
+void* lstAppendPointerStaticPool(laStaticMemoryPool* mph, laListHandle* h, void* p);
+void* lstPopPointerLeave(laListHandle* h);
+void lstRemovePointerItemNoFree(laListHandle* h, laListItemPointer* lip);
+
+void lstMoveUp(laListHandle* h, laListItem* li);
+void lstMoveDown(laListHandle* h, laListItem* li);
+
+void  lstForAllItemsDo(laListDoFunc func, laListHandle* hList);
+void lstForAllItemsDoLNRR(laListNonRecursiveDoFunc func, laListHandle* hList);
+void lstForAllItemsDo_DirectFree(laListDoFunc func, laListHandle* hList);
+void lstForAllItemsDo_arg_ptr(laListDoFuncArgp func, laListHandle* hList, void* arg);
+void lstForAllItemsDo_NonRecursive_Root(laListHandle* FirstHandle, laListNonRecursiveDoFunc func, int bFreeItem, void* custom_data, laListCustomDataRemover remover);
+void lstCopy_NonRecursive_Root(laListHandle* FromHandle, laListHandle* ToHandle, int SizeEachNode, laListNonRecursiveCopyFunc func, void* custom_data, laListCustomDataRemover remover);
+void lstAddNonRecursiveListHandle(laListNonRecursiveRoot* root, laListHandle* newHandle, laListNonRecursiveDoFunc nrFunc, int bFreeList, void* custom_data, laListCustomDataRemover remover);
+void lstAddNonRecursiveListCopier(laListNonRecursiveRoot* root, laListHandle* oldHandle, laListHandle* newHandle, int sizeEach, laListNonRecursiveCopyFunc nrCpyFunc, void* custom_data, laListCustomDataRemover remover);
+void* lstFindItem(void* CmpData, laCompareFunc func, laListHandle* hList);
+void lstCombineLists(laListHandle* dest, laListHandle* src);
+void lstDestroyList(laListHandle* hlst);
+void* lstReMatch(laListHandle* SearchHandle, laListHandle* CurrentHandle, void* ItemToFind);
+typedef int(*MatcherFunc)(void*, void*);
+void* lstReMatchEx(laListHandle* SearchHandle, laListHandle* CurrentHandle, void* ItemToFind, MatcherFunc func);
+
+void lstAddElement(laListHandle* hlst, void* ext);
+void lstDestroyElementList(laListHandle* hlst);
+
+void hsh256InsertItemCSTR(laHash256* hash, laListItem* li, char * buckle);
+void hsh256InsertItem(laHash256* hash, laListItem* li, char buckle);
+void hsh65536InsertItem(laHash65536* hash, laListItem* li, long buckle);
+
+void hsh65536Init(laHash65536** h);
+void hshFree(laHash65536** h);
+laListHandle* hsh65536DoHashLongPtr(laHash65536* hash, unsigned long long buckle);
+laListHandle* hsh65536DoHashNUID(laHash65536* hash, char * NUID);
+laListHandle* hsh16MDoHashLongPtr(laHash16M* hash, long long buckle);
+laListHandle* hsh16MDoHashNUID(laHash16M* hash, char * NUID);
+
+laListItem* hsh256FindItemSTR(laHash256* hash, laCompareFunc func, char * buckle);
+unsigned char hsh256DoHashSTR(char * buckle);
+
+// Leave memory to undo system to free later.
+#define memLeave(data) (data)
+
+void memResetByteCount();
+int memGetByteCount();
+void* memGetHead(void* UserMem, int* HyperLevel);
+laListHandle* memGetUserList(void* UserMem);
+laMemoryPool *memInitPool(int NodeSize, int HyperLevel);
+void memInitPoolSmall(laMemoryPool* mph, int NodeSize);
+laMemoryPoolPart* memNewPoolPart(laMemoryPool* mph);
+void* memAcquireH(laMemoryPool* Handle);
+void* memAcquireSimple(int Size);
+void* memAcquireNoAppend(int Size);
+void* memAcquireHyperNoAppend(int Size);
+void* memAcquire(int Size);
+void* memAcquireHyper(int Size);
+void memFree(void* Data);
+void memDestroyPool(laMemoryPool* Handle);
+void memNoLonger();
+void memMarkClean(void* HyperUserMem);
+
+laStaticMemoryPoolNode* memNewStaticPool(laStaticMemoryPool* smp);
+void* memStaticAcquire(laStaticMemoryPool*smp, int size);
+void* memStaticAcquireThread(laStaticMemoryPool*smp, int size);
+void* memStaticDestroy(laStaticMemoryPool*smp);
+
+NEED_STRUCTURE(laSubProp);
+
+void memAssignRef(void* This, void** ptr, void* instance);
+void memAssignRefSafe(laSubProp* sp, void* This, void** ptr, void* instance);
+
+int strGetStringTerminateBy(char * content, char terminator, char * Out);
+int strHeadOfStringMatch(char * Str, char * SubStr);
+int strSkipSegmet(char ** pivot, char * content);
+char * strGetLastSegment(char * Content, char Seperator);
+void strDiscardLastSegmentSeperateBy(char * Content, char Seperator);
+void strDiscardSameBeginningSeperatedBy(char * s1, char * s2, char ** Result1, char ** Result2, char Seperator);
+int strCountSegmentSeperateBy(char * Content, char Seperator);
+void strMakeDifferentName(char * Target);
+
+void strReplaceCharacter(char * Str, char Find, char Replace);
+void strToUpperCase(char * Str);
+void strToLowerCase(char * Str);
+
+laStringSplitor* strSplitPath(char * path);
+int strMakeInstructions(laStringSplitor** result,char * content);
+laStringPart* strGetArgument(laStringSplitor* ss, char * content);
+char * strGetArgumentString(laStringSplitor* ss, char * content);
+int strArgumentMatch(laStringSplitor* ss, char * id, char * value);
+int strDestroyStringSplitor(laStringSplitor** ss);
+
+int strGetIntSimple(char * content);
+real strGetFloatSimple(char * content);
+
+void strConvInt_CString(int src, char * dest, int lenth);
+void strConvFloat_CString(real src, char * dest, int lenth);
+
+void strCopyFull(char * dest, char * src);
+void strCopySized(char * dest, int LenthLim, char * src);
+#define strAppend strcat
+void strPrintFloatAfter(char * dest, int LenthLim, int bits, real data);
+void strPrintIntAfter(char * dest, int LenthLim, int data);
+int strSame(char * src, char *dest);
+void strEscapePath(char* OutCanBeSame, char* path);
+
+void strSafeDestroy(laSafeString** ss);
+void strSafeSet(laSafeString** ss, char * Content);
+void strSafeAppend(laSafeString **ss, char *Content);
+void strSafePrint(laSafeString **ss, char *Format, ...);
+void strSafePrintV(laSafeString **ss, char *Format, va_list arg);
+
+void strSafeDump();
+
+
+void strBeginEdit(laStringEdit** se, char * FullStr);
+char* strGetEditString(laStringEdit *se, int SelectionOnly);
+char* strEndEdit(laStringEdit** se, int FreeString);
+void strSetEditViewRange(laStringEdit* se, int Lines, int Cols);
+void strEnsureCursorVisible(laStringEdit* se);
+void strRemoveLine(laStringEdit* se, laStringLine* sl);
+void strRemoveLineI(laStringEdit* se, int LineIndex);
+void strSetCursor(laStringEdit* se, int LineIndex, int BeforeIndex);
+void strMoveCursor(laStringEdit* se, int Left, int Select);
+void strMoveCursorLine(laStringEdit *se, int Up, int Select);
+int strHasSelection(laStringEdit* se);
+void strCancelSelect(laStringEdit *se);
+void strLazySelect(laStringEdit *se);
+void strEndSelect(laStringEdit *se);
+void strSelectLineAll(laStringEdit* se);
+void strDeselectAll(laStringEdit* se);
+void strPanFoward(uint32_t * str, int Before, int Offset);
+void strSquishBackward(uint32_t * str, int Before, int EndBefore);
+void strClearSelection(laStringEdit* se);
+laStringLine *strGetCursorLine(laStringEdit *se, int* IndexIfLast);
+laStringLine* strGetBeginLine(laStringEdit* se);
+void strInsertChar(laStringEdit* se, uint32_t a);
+void strBackspace(laStringEdit* se);
+void strMoveView(laStringEdit *se, int DownLines, int RightCharacters);
+
+void transNewLanguage(const char * LanguageID);
+void transSetLanguage(const char * LanguageID);
+void transDumpMissMatchRecord(const char * filename);
+void transNewEntry(const char * Target, const char * replacement);
+char * transLate(char * Target);
+void transState(void* UNUSED, int val);
+void transInitTranslation_zh_cn();
+
+
+void laOpenInternetLink(char * link);
+
+

+ 931 - 0
source/lagui/resources/la_modelling.c

@@ -0,0 +1,931 @@
+#include "../la_5.h"
+
+extern LA MAIN;
+extern struct _tnsMain *T;
+
+int OPCHK_ThereIsActiveObject(laPropPack *This, laStringSplitor *ss){
+    if(!This || !This->EndInstance){ return 0; }
+    laCanvasExtra* ex=This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject; if(!mo) return 0; return 1;
+}
+int OPINV_ToggleEdit(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject; if(!mo) return 0;
+    if(mo->Base.Type!=TNS_OBJECT_MESH) return LA_CANCELED;
+    if(mo->Mode==TNS_MESH_EDIT_MODE) tnsMeshLeaveEditMode(mo); else tnsMeshEnterEditMode(mo);
+    laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Toggle edit mode", TNS_HINT_GEOMETRY);
+    laNotifyUsers("tns.world");
+    return LA_FINISHED_PASS;
+}
+
+STRUCTURE(MSelectData){
+    tnsOffscreen* FBO;
+    tnsTexture* Color;
+    void** Refs; int next,max;
+};
+MSelectData* la_InitSelectData(int w, int h, tnsCamera* camera){
+    MSelectData* sd=memAcquireSimple(sizeof(MSelectData));
+    if (!sd->FBO || sd->FBO->pColor[0]->Height != h || sd->FBO->pColor[0]->Width != w){
+        if (sd->FBO) tnsDelete2DOffscreen(sd->FBO);
+        sd->FBO = tnsCreate2DOffscreen(GL_RGB, w, h, 0, 1); sd->Color=sd->FBO->pColor[0];
+    }
+    tnsDrawToOffscreen(sd->FBO, 1, 0);
+    return sd;
+}
+void la_AssignObjectSelectIDRecursive(tnsObject* root, MSelectData* sd){
+    for(laListItemPointer*lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
+        tnsObject* o=lip->p; if(!o) continue;
+        arrEnsureLength(&sd->Refs, sd->next, &sd->max, sizeof(tnsObject*));
+        sd->Refs[sd->next]=o; o->SelectID=sd->next; sd->next++;
+        if(o->ChildObjects.pFirst){ la_AssignObjectSelectIDRecursive(o,sd); }
+    }
+}
+void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* camera){
+    arrEnsureLength(&sd->Refs,0,&sd->max,sizeof(tnsObject*));
+    sd->next++; // starting from 1;
+    la_AssignObjectSelectIDRecursive(root, sd);
+    if(sd->next==1) return; int w=sd->Color->Width, h=sd->Color->Height;
+    tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
+    tnsEnableShaderv(T->SelectionShader);
+    glDisableVertexAttribArray(T->SelectionShader->iColor); glVertexAttrib4f(T->SelectionShader->iColor,0,0,0,0);
+    tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
+    tnsApplyCameraView(w,h,camera);
+    glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+    glEnable(GL_DEPTH_TEST);
+    tnsDrawObjectTree(root,0,0);
+    glDisable(GL_DEPTH_TEST);
+}
+void la_PopulateSelectDataVertices(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera){
+    arrEnsureLength(&sd->Refs,0,&sd->max,sizeof(tnsMVert*));
+    if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
+    for(tnsMVert* v=mo->mv.pFirst;v;v=v->Item.pNext){
+        arrEnsureLength(&sd->Refs, v->i, &sd->max, sizeof(tnsObject*));
+        sd->Refs[v->i]=v; sd->next=TNS_MAX2(v->i, sd->next);
+    }
+    sd->next++;
+    int w=sd->Color->Width, h=sd->Color->Height;
+    tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
+    tnsEnableShaderv(T->SelectionShader);
+    tnsViewportWithScissor(0,0,w,h);tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
+    tnsApplyCameraView(w,h,camera);
+    glClearColor(0,0,0,0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+    glEnable(GL_DEPTH_TEST);
+    tnsPushMatrix(); tnsApplyObjectMatrix(mo);
+    tnsDrawBatch(mo->Batch, "verts_select",0,0);
+    tnsPopMatrix();
+    glDisable(GL_DEPTH_TEST);
+}
+void la_PadSelectionBuffer(uint8_t* buf, int w, int h, int sx, int sy, int ex, int ey, int real_endx){
+    if(!sx&&!sy&&!ex&&!ey) return;
+    uint8_t* pad=calloc(1,sizeof(uint8_t)*4*w*h);
+    for(int i=0;i<h;i++){
+        if(i<sy || i>=h-ey){ memset(&pad[i*w*4],0,w*4); continue; }
+        for(int j=0;j<w;j++){
+            if(j<sx || j>=w-sx){ memset(&pad[(i*w+j)*4],0,4); continue; }
+            memcpy(&pad[(i*w+j)*4], &buf[((i-sy)*(real_endx-sx)+j-sx)*4], 4);
+        }
+    }
+    memcpy(buf,pad,sizeof(uint8_t)*4*w*h);
+    free(pad);
+}
+uint8_t* la_ReadSelection(MSelectData* sd, u8bit* buf, int x, int y, int w, int h){
+    glFlush(); glFinish(); 
+    glGetError();
+    glBindFramebuffer(GL_READ_FRAMEBUFFER, sd->FBO->FboHandle);
+    glReadBuffer(GL_COLOR_ATTACHMENT0);
+    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+    glReadPixels(x,y,w,h, GL_RGBA, GL_UNSIGNED_BYTE, buf);
+    return buf;
+}
+uint8_t* la_ReadSelectionRadius(MSelectData* sd, int uix, int uiy, int radius){
+    int w=radius*2; int vh=sd->Color->Height,vw=sd->Color->Width;
+    uint8_t* buf=calloc(1,sizeof(uint8_t)*4*w*w);
+    int startx=uix-radius, starty=vh-uiy-radius, endx=uix+radius, endy=vh-uiy+radius;
+    TNS_CLAMP(startx,0,vw);TNS_CLAMP(endx,0,vw);TNS_CLAMP(starty,0,vh);TNS_CLAMP(endy,0,vh);
+    int _startx=TNS_MAX2(startx,0), _starty=TNS_MAX2(starty,0), _endx=TNS_MIN2(endx,vw), _endy=TNS_MIN2(endy,vh);
+    la_ReadSelection(sd, buf, _startx, _starty, _endx-_startx, _endy-_starty);
+    la_PadSelectionBuffer(buf, w, w, _startx-startx, _starty-starty, endx-_endx, endy-_endy,_endx);
+    return buf;
+}
+uint8_t* la_ReadSelectionBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2){
+    int vh=sd->Color->Height,vw=sd->Color->Width;
+    if(uix2<uix) LA_SWAP(int,uix,uix2); if(uiy2<uiy) LA_SWAP(int,uiy,uiy2);
+    TNS_CLAMP(uix,0,vw);TNS_CLAMP(uix2,0,vw);TNS_CLAMP(uiy,0,vh);TNS_CLAMP(uiy2,0,vh);
+    int w=uix2-uix, h=uiy2-uiy;
+    uint8_t* buf=calloc(1,sizeof(uint8_t)*4*w*h);
+    int startx=uix, starty=vh-uiy2, endx=uix+w, endy=starty+h;
+    int _startx=TNS_MAX2(startx,0), _starty=TNS_MAX2(starty,0), _endx=TNS_MIN2(endx,vw), _endy=TNS_MIN2(endy,vh);
+    la_ReadSelection(sd, buf, _startx, _starty, _endx-_startx, _endy-_starty);
+    la_PadSelectionBuffer(buf, w, h, _startx-startx, _starty-starty, endx-_endx, endy-_endy,_endx);
+    return buf;
+}
+int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius){
+    uint8_t* buf=la_ReadSelectionRadius(sd, uix, uiy, radius); if(!buf) return 0;
+    int w=radius*2; int MinD=INT_MAX; int MinID=0, d;
+    for(int i=0;i<w;i++){
+        for(int j=0;j<w;j++){
+            uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|(p[2]<<16);
+            if(id && (d=tnsDistIdv2(i,j, radius, radius))<MinD ){ MinD=d; MinID=id; }
+            //printf("%d ",buf[(i*w+j)*4]);
+        }
+        //printf("\n");
+    }
+    free(buf);
+    return MinID;
+}
+int* la_SelectGetBox(MSelectData* sd, int uix, int uiy, int uix2, int uiy2, int* r_length){
+    uint8_t* buf=la_ReadSelectionBox(sd, uix, uiy, uix2, uiy2); if(!buf) return 0;
+    int vh=sd->Color->Height,vw=sd->Color->Width;
+    if(uix2<uix) LA_SWAP(int,uix,uix2); if(uiy2<uiy) LA_SWAP(int,uiy,uiy2);
+    TNS_CLAMP(uix,0,vw);TNS_CLAMP(uix2,0,vw);TNS_CLAMP(uiy,0,vh);TNS_CLAMP(uiy2,0,vh);
+    int w=uix2-uix, h=uiy2-uiy;
+    int* ids=0; int next=0,max=0;
+    arrEnsureLength(&ids, next, &max, sizeof(int));
+    for(int i=0;i<h;i++){
+        for(int j=0;j<w;j++){
+            uint8_t* p=&buf[(i*w+j)*4]; int id=(p[0])|(p[1]<<8)|(p[2]<<16);
+            if(id){ int found=0;
+                for(int a=0;a<next;a++){ if(ids[a]==id){ found=1; break; } }
+                if(!found){
+                    arrEnsureLength(&ids, next, &max, sizeof(int)); ids[next]=id; next++; }
+            }
+        }
+    }
+    free(buf);
+    *r_length=next;
+    return ids;
+}
+void la_FreeSelectData(MSelectData* sd){
+    tnsDelete2DOffscreen(sd->FBO);
+    free(sd->Refs);
+    memFree(sd);
+}
+
+int OPCHK_ViewportAndSceneExists(laPropPack *This, laStringSplitor *ss){
+    if(!This || !This->EndInstance){ return 0; } laCanvasExtra* ex=This->EndInstance;
+    laUiItem* ui=ex->ParentUi; tnsObject* root=ui?ui->PP.EndInstance:0;
+    if(!ex->ViewingCamera || !root){ return 0; }
+    return 1;
+}
+void la_DoObjectSelect(tnsObject* root, tnsObject* o, laCanvasExtra* e, int DeselectAll, int Select, int Toggle){
+    if(DeselectAll){ tnsDeselectAllObjects(root); memAssignRef(e,&e->ActiveObject,0); }
+    if(o){ tnsSelectObject(o, Select, o==e->ActiveObject?0:Toggle); memAssignRef(e,&e->ActiveObject,o); }
+}
+void la_DoMeshSelect(tnsMeshObject* mo, tnsMVert* mv, int DeselectAll, int Select, int Toggle){
+    if(DeselectAll){ tnsMMeshDeselectAll(mo); }
+    if(mv){ tnsMMeshSelectVert(mo,mv,Select,Toggle); }
+}
+
+#define LA_SELECT_MODE_BOX 1
+STRUCTURE(MSelectExtra){
+    MSelectData* sd;
+    tnsObject* root;
+    tnsObject* mo;
+    tnsCamera* cam;
+    int Mode;
+    int InSelect;
+};
+
+int OPINV_Select(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject;
+
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "toggle")){
+        if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
+            if(tnsMMeshAnySelected(mo)) tnsMMeshDeselectAll(mo); else tnsMMeshSelectAll(mo);
+            tnsInvaliateMeshBatch(mo);
+        }else{
+            if(tnsAnyObjectsSelected(root)) tnsDeselectAllObjects(root); else tnsSelectAllObjects(root);
+        }
+        laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world");
+        return LA_FINISHED;
+    }
+    
+    MSelectData* sd=la_InitSelectData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c);
+
+    int DeselectAll=1;
+    int Append=e->SpecialKeyBit&LA_KEY_SHIFT; if(Append) DeselectAll=0;
+    
+    if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
+        la_PopulateSelectDataVertices(sd, mo, ex->ViewingCamera);
+        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
+            MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
+            ex->OnX=e->x; ex->OnX=e->y;
+            a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->mo=mo; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
+        }
+        int id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH*2)-1;
+        tnsMVert* mv;
+        if(id>=0 && id<sd->next){ mv=sd->Refs[id]; }
+        la_DoMeshSelect(mo, mv, DeselectAll, 1, 1); tnsMMeshEnsureSelectionFromVert(mo);
+        tnsInvaliateMeshBatch(mo);
+        laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world");
+    }else{
+        la_PopulateSelectDataObjects(sd,root,ex->ViewingCamera);
+        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "box")){
+            MSelectExtra* se=memAcquire(sizeof(MSelectExtra));
+            ex->OnX=e->x; ex->OnX=e->y;
+            a->CustomData=se; se->sd=sd; se->Mode=LA_SELECT_MODE_BOX; se->cam=c; ex->DrawCursor=1; se->root=root; return LA_RUNNING;
+        }
+        int id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH*2);
+        if(id && id<sd->next){ la_DoObjectSelect(root, sd->Refs[id], ex, DeselectAll, 1, 1);  }
+        else{ la_DoObjectSelect(root, 0, ex, DeselectAll, 1, 1); }
+        laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world");
+    }
+
+    la_FreeSelectData(sd);
+    
+    return LA_FINISHED_PASS;
+}
+int OPMOD_Select(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return;
+    tnsMeshObject* mo=ex->ActiveObject;
+    MSelectExtra* se=a->CustomData;
+
+    if(e->Type==LA_L_MOUSE_DOWN){ se->InSelect=1; ex->DrawCursor=2; ex->ClickedX=e->x; ex->ClickedY=e->y; laRedrawCurrentPanel(); }
+    if(e->Type&LA_MOUSE_EVENT){ ex->OnX=e->x; ex->OnY=e->y; laRedrawCurrentPanel(); }
+    if(e->Type==LA_R_MOUSE_DOWN || (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE)){
+        ex->DrawCursor=0; la_FreeSelectData(se->sd); laNotifyUsers("tns.world"); return LA_FINISHED;
+    }
+
+    int DeselectAll=1;
+    int Append=e->SpecialKeyBit&LA_KEY_SHIFT; if(Append) DeselectAll=0;
+    int Remove=e->SpecialKeyBit&LA_KEY_ALT; if(Remove) DeselectAll=0;
+
+    if(se->InSelect && e->Type==LA_L_MOUSE_UP){
+        if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
+            la_DoMeshSelect(mo, 0, DeselectAll, 0, 0);
+            int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX-ui->L, ex->ClickedY-ui->U, e->x-ui->L, e->y-ui->U, &len);
+            for(int i=0;i<len;i++){
+                int id=ids[i]-1; tnsMVert* mv; if(id>=0 && id<se->sd->next){ mv=se->sd->Refs[id]; }
+                la_DoMeshSelect(mo, mv, 0, !Remove, 0);
+            }
+            tnsMMeshEnsureSelectionFromVert(mo);
+            tnsInvaliateMeshBatch(mo);
+        }else{
+            la_DoObjectSelect(se->root, 0, ex, DeselectAll, 0, 0);
+            int len; int* ids=la_SelectGetBox(se->sd, ex->ClickedX, ex->ClickedY, e->x-ui->L, e->y-ui->U, &len);
+            for(int i=0;i<len;i++){
+                int id=ids[i]; if(id && id<se->sd->next){ la_DoObjectSelect(se->root, se->sd->Refs[id], ex, 0, !Remove, 0);  }
+            }
+        }
+        laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world");
+        ex->DrawCursor=0;
+        la_FreeSelectData(se->sd);
+        laRedrawCurrentPanel();
+        return LA_FINISHED;
+    }
+    
+    return LA_RUNNING;
+}
+
+
+#define LA_TRANSFORM_MODE_GRAB   1
+#define LA_TRANSFORM_MODE_ROTATE 2
+#define LA_TRANSFORM_MODE_SCALE  3
+
+STRUCTURE(MTOrigObject){
+    tnsObject* o;
+    tnsMatrix44d Global;
+    tnsMatrix44d Local;
+    int Discard;
+};
+STRUCTURE(MTOrigMVert){
+    tnsVector3d p;
+    tnsVector3d origp;
+    tnsMVert* mv;
+};
+STRUCTURE(MTransformData){
+    tnsMatrix44d Delta;
+    tnsMatrix44d ViewProjection;
+    tnsVector4d Up,Right,Foward;
+    tnsVector4d TCenter;
+    int CenterX,CenterY; real Initial;
+    tnsObject* mo; tnsMatrix44d obmatinv;
+    tnsCamera* c; tnsObject* root;
+    int w,h;
+    void* Originals; int next,max;
+    int mode;
+    int LockAxis[3];
+    int Local;
+    real DeltaVal, UserDeltaVal;
+    laStringEdit* Entry; int UseUserDelta;
+};
+
+MTransformData* la_InitTransformData(int w, int h, tnsCamera* c){
+    MTransformData* td=memAcquireSimple(sizeof(MTransformData));
+    tnsVector4d pu={0,1,0,0}, pr={1,0,0,0}, pf={0,0,1};
+    tnsGetCameraMovingDeltas(c,w,h,1,0,pr); pr[2]=0; pr[3]=0;
+    tnsGetCameraMovingDeltas(c,w,h,0,-1,pu); pu[2]=0; pu[3]=0;
+    tnsMatrix44d inv; tnsInverse44d(inv,c->Base.GlobalTransform);
+    tnsApplyRotation43d(td->Up,inv,pu);
+    tnsApplyRotation43d(td->Right,inv,pr);
+    tnsApplyRotation43d(td->Foward,inv,pf);
+
+    tnsGetCameraViewProjection(td->ViewProjection, w,h,c);
+    td->c=c; td->w=w; td->h=h;
+    strBeginEdit(&td->Entry, "");
+    return td;
+}
+void la_GetTransformInitialScale(MTransformData* td, laUiItem* ui, int x, int y){ td->Initial=tnsDistIdv2(x-ui->L,y-ui->U,td->CenterX,td->CenterY); }
+void la_GetTransformInitialRotation(MTransformData* td, laUiItem* ui, int x, int y){ td->Initial=atan2(y-ui->U-td->CenterY,x-ui->L-td->CenterX); }
+void la_GetTransformCenter2D(MTransformData* td){
+    tnsVector4d vp; tnsApplyTransform44d(vp,td->ViewProjection,td->TCenter);
+    if(td->c->CameraType==TNS_PRESPECTIVE_CAMERA){ tnsVectorMultiSelf3d(vp, 1/vp[3]); }
+    td->CenterX = (vp[0]/2+0.5f)*td->w; td->CenterY=(-vp[1]/2+0.5f)*td->h;
+    if(td->CenterX<0||td->CenterY<0) { td->CenterX=td->w/2; td->CenterY=td->h/2; }
+}
+int la_AddTransformObjectsRecursive(MTransformData* td, tnsObject*root){
+    int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
+        tnsObject* o=lip->p; if(o->ChildObjects.pFirst) any+=la_AddTransformObjectsRecursive(td,o);
+        if(!o->Flags&TNS_OBJECT_FLAGS_SELECTED) continue;
+        arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigObject));
+        MTOrigObject* to=arrElement(td->Originals, td->next, sizeof(MTOrigObject)); td->next++; to->o=o;
+        memcpy(to->Global, o->GlobalTransform, sizeof(tnsMatrix44d));
+        memcpy(to->Local, o->SelfTransform, sizeof(tnsMatrix44d));
+        tnsVectorAccum3d(td->TCenter,o->GLocation); any++;
+        int discard=0; tnsObject* po=o; while(po=po->ParentObject){ if(po->Flags&TNS_OBJECT_FLAGS_SELECTED){ discard=1; break;} } if(discard) to->Discard=1;
+    }
+    return any;
+}
+int la_PopulateTransformObjects(MTransformData* td, tnsObject* root){
+    arrEnsureLength(&td->Originals, 0, &td->max, sizeof(MTOrigObject));
+    int any=la_AddTransformObjectsRecursive(td,root);
+    tnsVectorMultiSelf3d(td->TCenter, 1.0f/any);
+    la_GetTransformCenter2D(td);
+    return any;
+}
+int la_PopulateTransformVerticies(MTransformData* td, tnsMeshObject* mo){
+    int any=0; td->mo=mo;
+    arrEnsureLength(&td->Originals, 0, &td->max, sizeof(MTOrigMVert));
+    tnsInverse44d(td->obmatinv, mo->Base.GlobalTransform);
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){
+        if(!mv->flags&TNS_MESH_FLAG_SELECTED) continue;
+        arrEnsureLength(&td->Originals, td->next, &td->max, sizeof(MTOrigMVert));
+        MTOrigMVert* to=arrElement(td->Originals, td->next, sizeof(MTOrigMVert)); td->next++; to->mv=mv;
+        tnsApplyTransform43d(to->p, mo->Base.GlobalTransform, mv->p);
+        memcpy(to->origp, mv->p, sizeof(tnsVector3d)); any++;
+        tnsVectorAccum3d(td->TCenter,to->p);
+    }
+    tnsVectorMultiSelf3d(td->TCenter, 1.0f/any);
+    la_GetTransformCenter2D(td);
+    return any;
+}
+void la_ApplyTranslation(MTransformData* td, int x, int y){
+    tnsMatrix44d trans; tnsVector3d deltay,delta; tnsVector3d gp;
+    tnsVectorMulti3d(delta, td->Right, x); tnsVectorMulti3d(deltay, td->Up, y); tnsVectorAccum3d(delta, deltay);
+    tnsVector3d use_delta={LA_COLOR3(delta)}; real len;
+    if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ len=tnsLength3d(delta); }
+    if(td->LockAxis[0]>0){ use_delta[1]=use_delta[2]=0; real l=fabs(use_delta[0]); use_delta[0]=l?use_delta[0]*len/l:1e-7; }
+    if(td->LockAxis[1]>0){ use_delta[0]=use_delta[2]=0; real l=fabs(use_delta[1]); use_delta[1]=l?use_delta[1]*len/l:1e-7; }
+    if(td->LockAxis[2]>0){ use_delta[0]=use_delta[1]=0; real l=fabs(use_delta[2]); use_delta[2]=l?use_delta[2]*len/l:1e-7; }
+    if(td->LockAxis[0]<0){ use_delta[0]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l:0); }
+    if(td->LockAxis[1]<0){ use_delta[1]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l:0); }
+    if(td->LockAxis[2]<0){ use_delta[2]=0; real l=tnsLength3d(use_delta); tnsVectorMultiSelf3d(use_delta, l?len/l:0); }
+    td->DeltaVal=tnsLength3d(use_delta);
+    if(td->UseUserDelta){
+        tnsVectorMultiSelf3d(use_delta,1/tnsLength3d(use_delta)*td->UserDeltaVal);
+        tnsVector3d lock={ td->LockAxis[0], td->LockAxis[1], td->LockAxis[2] };
+        real dir=tnsDot3d(use_delta, lock, 0); tnsVectorMultiSelf3d(use_delta,(td->UserDeltaVal*dir<=0)?-1:1);
+        td->DeltaVal=td->UserDeltaVal; 
+    }
+    if(!td->mo){
+        for(int i=0;i<td->next;i++){
+            MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
+            if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
+            tnsGlobalMatrixChanged(to->o, 0); tnsMoveObjectGlobal(to->o, LA_COLOR3(use_delta));
+        }
+    }else{
+        tnsMakeTranslationMatrix44d(trans, LA_COLOR3(use_delta));
+        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
+            tnsApplyTransform43d(gp, trans, to->p); tnsApplyTransform43d(to->mv->p, td->obmatinv, gp);
+        }
+        tnsInvaliateMeshBatch(td->mo);
+    }
+}
+void la_ApplyScale(MTransformData* td, int uix, int uiy){
+    tnsMatrix44d trans; real d=tnsDistIdv2(uix,uiy,td->CenterX,td->CenterY); if(!td->Initial){ td->Initial=100; }
+    real s=d/td->Initial; tnsVector3d gp;
+    td->DeltaVal=s; if(td->UseUserDelta) td->DeltaVal=s=td->UserDeltaVal;
+    if(!td->mo){
+        for(int i=0;i<td->next;i++){
+            MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
+            if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
+            tnsGlobalMatrixChanged(to->o, 0); tnsScaleObject(to->o, s, LA_COLOR3(td->TCenter));
+        }
+    }else{
+        tnsMakeScaleMatrix44d(trans,s,s,s);
+        tnsMatrix44d t1,t2,t3; tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->TCenter)); tnsInverse44d(t2,t1);
+        tnsMatrix44d final; tnsMultiply44d(t3,t1,trans); tnsMultiply44d(final,t3,t2);
+        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
+            tnsApplyTransform43d(gp, final, to->p); tnsApplyTransform43d(to->mv->p, td->obmatinv, gp);
+        }
+        tnsInvaliateMeshBatch(td->mo);
+    }
+}
+void la_ApplyRotation(MTransformData* td, int uix, int uiy){
+    tnsMatrix44d trans; real a=atan2(uiy-td->CenterY,uix-td->CenterX);
+    real angle=a-td->Initial; tnsVector3d gp; tnsVector3d LimFoward={0}; real* use_forward=td->Foward;
+    if(td->LockAxis[0]||td->LockAxis[1]||td->LockAxis[2]){ use_forward=LimFoward; }
+    if(td->LockAxis[0]){ LimFoward[0]=1; }
+    if(td->LockAxis[1]){ LimFoward[1]=1; }
+    if(td->LockAxis[2]){ LimFoward[2]=1; }
+     if(td->UseUserDelta) angle=rad(td->UserDeltaVal); td->DeltaVal=deg(angle);
+    if(!td->mo){
+        for(int i=0;i<td->next;i++){
+            MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject)); memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
+            if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
+            tnsGlobalMatrixChanged(to->o, 0); tnsRotateObjectGlobal(to->o,LA_COLOR3(use_forward),angle,LA_COLOR3(td->TCenter));
+        }
+    }else{
+        tnsMakeRotationMatrix44d(trans, angle, LA_COLOR3(use_forward));
+        tnsMatrix44d t1,t2,t3; tnsMakeTranslationMatrix44d(t1,LA_COLOR3(td->TCenter)); tnsInverse44d(t2,t1);
+        tnsMatrix44d final; tnsMultiply44d(t3,t1,trans); tnsMultiply44d(final,t3,t2);
+        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert));
+            tnsApplyTransform43d(gp, final, to->p); tnsApplyTransform43d(to->mv->p, td->obmatinv, gp);
+        }
+        tnsInvaliateMeshBatch(td->mo);
+    }
+}
+void la_CancelTransformObjects(MTransformData* td){
+    if(!td->mo){
+        for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
+            if(to->Discard){ tnsSelfMatrixChanged(to->o,1); continue; }
+            memcpy(to->o->GlobalTransform, to->Global,sizeof(tnsMatrix44d));
+            tnsGlobalMatrixChanged(to->o, 1);
+        }
+    }else{
+        for(int i=0;i<td->next;i++){ MTOrigMVert* to=arrElement(td->Originals, i, sizeof(MTOrigMVert)); tnsVectorCopy3d(to->origp,to->mv->p); }
+        tnsInvaliateMeshBatch(td->mo);
+    }
+}
+void la_RecordTransformDifferences(MTransformData* td){
+    if(!td->mo){
+        for(int i=0;i<td->next;i++){ MTOrigObject* to=arrElement(td->Originals, i, sizeof(MTOrigObject));
+            laRecordInstanceDifferences(to->o, "tns_object");
+        } laPushDifferences("Object Transformation", TNS_HINT_TRANSFORM);
+    }else{
+        laRecordInstanceDifferences(td->mo, "tns_mesh_object"); laPushDifferences("Mesh transformation", TNS_HINT_GEOMETRY);
+        tnsInvaliateMeshBatch(td->mo);
+    }
+}
+void la_FreeTransformData(MTransformData* td){
+    free(td->Originals);
+    strEndEdit(&td->Entry, 1);
+    memFree(td);
+}
+void la_MakeTransformOperatorHint(laOperator* a, MTransformData* td){
+    strSafeDestroy(&a->RuntimeHint);
+    strSafePrint(&a->RuntimeHint, "%s  ",
+        td->mode==LA_TRANSFORM_MODE_GRAB?"Grab":td->mode==LA_TRANSFORM_MODE_ROTATE?"Rotate":td->mode==LA_TRANSFORM_MODE_SCALE?"Scale":"");
+    char* entry=strGetEditString(td->Entry,0);
+    strSafePrint(&a->RuntimeHint, "Delta: %.3lf [🔢 %s]  🆇🆈🆉 Lock axis: %s  ", td->DeltaVal, (entry&&entry[0])?entry:"Type...",
+        td->LockAxis[0]?"X":td->LockAxis[1]?"Y":td->LockAxis[2]?"Z":"None");
+    free(entry);
+    if(td->mode==LA_TRANSFORM_MODE_GRAB){ strSafePrint(&a->RuntimeHint, "🡅🆇🆈🆉 Reverse: %s  ",
+        (td->LockAxis[0]<0||td->LockAxis[1]<0||td->LockAxis[2]<0)?"Yes":"No"); }
+    if(td->mode!=LA_TRANSFORM_MODE_GRAB){ strSafePrint(&a->RuntimeHint,"🅶 Grab  "); }
+    if(td->mode!=LA_TRANSFORM_MODE_SCALE){ strSafePrint(&a->RuntimeHint,"🆂 Scale  "); }
+    if(td->mode!=LA_TRANSFORM_MODE_ROTATE){ strSafePrint(&a->RuntimeHint,"🆁 Rotate  "); }
+}
+int la_InitTransform(laOperator* a, laEvent* e, int mode){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject;
+
+    MTransformData* td=la_InitTransformData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c);
+    a->CustomData = td;
+    td->mode=mode;
+    td->root=root;
+
+    int ret=0;
+    if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
+        if(la_PopulateTransformVerticies(td, mo)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
+    }else{
+        if(la_PopulateTransformObjects(td,root)){ ex->ClickedX=e->x; ex->ClickedY=e->y; ret=1; }
+    }
+    
+    if(ret){
+        if(mode==LA_TRANSFORM_MODE_SCALE){ la_GetTransformInitialScale(td,ui,e->x,e->y); ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
+        elif(mode==LA_TRANSFORM_MODE_ROTATE){ la_GetTransformInitialRotation(td,ui,e->x,e->y); ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
+        ex->TargetX=td->CenterX+ui->L; ex->TargetY=td->CenterY+ui->U; ex->OnX=e->x; ex->OnY=e->y;
+        la_MakeTransformOperatorHint(a, td);
+        laNotifyUsers("tns.world"); return 1;
+    }
+
+    return 0;
+}
+int OPINV_Grab(laOperator *a, laEvent *e){
+    if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB)) return LA_RUNNING; return LA_FINISHED_PASS;
+}
+int OPINV_Scale(laOperator *a, laEvent *e){
+    if(la_InitTransform(a, e, LA_TRANSFORM_MODE_SCALE)) return LA_RUNNING; return LA_FINISHED_PASS;
+}
+int OPINV_Rotate(laOperator *a, laEvent *e){
+    if(la_InitTransform(a, e, LA_TRANSFORM_MODE_ROTATE)) return LA_RUNNING; return LA_FINISHED_PASS;
+}
+int OPMOD_Transformation(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject;
+    MTransformData* td=a->CustomData;
+
+    if (e->Input=='x'||e->Input=='y'||e->Input=='z'||e->Input=='g'||e->Input=='s'||e->Input=='r'||
+        e->Input=='X'||e->Input=='Y'||e->Input=='Z'){ /*pass*/ }
+    else{ la_ProcessTextEdit(e, td->Entry, 0); }
+
+    char* entered;
+    if(entered=strGetEditString(td->Entry,0)){ int status;
+        if((status=sscanf(entered,"%lf",&td->UserDeltaVal)) && status!=EOF) td->UseUserDelta=1; else td->UseUserDelta=0; 
+        td->UserDeltaVal=fabs(td->UserDeltaVal); for(char*pc=entered;*pc;pc++){ if(*pc=='-') td->UserDeltaVal=-td->UserDeltaVal; } free(entered); 
+    }
+
+    if(e->Type==LA_KEY_DOWN){
+        int Other=1; if(e->SpecialKeyBit&LA_KEY_SHIFT){ Other=-1; }
+        if(e->key=='x'){ td->LockAxis[0]=Other*((Other<0&&td->LockAxis[0])?td->LockAxis[0]:!td->LockAxis[0]); td->LockAxis[1]=td->LockAxis[2]=0; }
+        if(e->key=='y'){ td->LockAxis[1]=Other*((Other<0&&td->LockAxis[1])?td->LockAxis[1]:!td->LockAxis[1]); td->LockAxis[0]=td->LockAxis[2]=0; }
+        if(e->key=='z'){ td->LockAxis[2]=Other*((Other<0&&td->LockAxis[2])?td->LockAxis[2]:!td->LockAxis[2]); td->LockAxis[0]=td->LockAxis[1]=0; }
+        if(e->key=='g' && td->mode!=LA_TRANSFORM_MODE_GRAB){ td->mode=LA_TRANSFORM_MODE_GRAB; ex->DrawCursor=0; }
+        if(e->key=='s' && td->mode!=LA_TRANSFORM_MODE_SCALE){ td->mode=LA_TRANSFORM_MODE_SCALE; la_GetTransformInitialScale(td,ui,e->x,e->y);ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
+        if(e->key=='r' && td->mode!=LA_TRANSFORM_MODE_ROTATE){ td->mode=LA_TRANSFORM_MODE_ROTATE; la_GetTransformInitialRotation(td,ui,e->x,e->y);ex->DrawCursor=LA_CANVAS_CURSOR_ARROW; }
+    }
+
+    if(e->Type==LA_MOUSEMOVE || e->Type==LA_KEY_DOWN){
+        switch(td->mode){
+            case LA_TRANSFORM_MODE_GRAB: la_ApplyTranslation(td,e->x-ex->ClickedX, e->y-ex->ClickedY); break;
+            case LA_TRANSFORM_MODE_SCALE: la_ApplyScale(td,e->x-ui->L, e->y-ui->U); break;
+            case LA_TRANSFORM_MODE_ROTATE: la_ApplyRotation(td,e->x-ui->L, e->y-ui->U); break;
+            default: break;
+        }
+        ex->OnX=e->x; ex->OnY=e->y;
+        laNotifyUsers("tns.world");
+    }
+
+    if(e->Type==LA_L_MOUSE_DOWN || (e->Type==LA_KEY_DOWN && e->key==LA_KEY_ENTER)){ ex->DrawCursor=0;
+        la_RecordTransformDifferences(td);
+        laNotifyUsers("tns.world"); la_FreeTransformData(td); return LA_FINISHED;
+    }
+    if(e->Type==LA_R_MOUSE_DOWN || e->Type==LA_ESCAPE_DOWN){ ex->DrawCursor=0;
+        la_CancelTransformObjects(td); laNotifyUsers("tns.world"); la_FreeTransformData(td); return LA_FINISHED;
+    }
+
+    la_MakeTransformOperatorHint(a, td);
+
+    return LA_RUNNING;
+}
+
+int la_ParentableRecursive(tnsObject* root, tnsObject* parent){
+    for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
+        tnsObject* o=lip->p; if(!o || !o->Flags&TNS_OBJECT_FLAGS_SELECTED || o==parent) continue;
+        if(!tnsCheckParentable(o,parent)) return 0;
+        if(!la_ParentableRecursive(o,parent)) return 0;
+    }return 1;
+}
+void la_MakeParentExecuteRecursive(tnsObject* root, tnsObject* parent, int Unparent, int KeepTransform){
+    for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
+        tnsObject* o=lip->p; if(!o || !o->Flags&TNS_OBJECT_FLAGS_SELECTED) continue;
+        if(Unparent) tnsUnparentObject(o, KeepTransform);
+        else tnsParentObject(o, parent, KeepTransform);
+        la_MakeParentExecuteRecursive(o,parent,Unparent,KeepTransform);
+    }
+    laNotifyUsers("tns.world");
+}
+int OPINV_MakeParent(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsObject* mo=ex->ActiveObject;
+
+    int Unparent=0,KeepTransform=1;
+    char* action=strGetArgumentString(a->ExtraInstructionsP,"action");
+    char* keep=strGetArgumentString(a->ExtraInstructionsP,"keep_transform");
+    if(strSame(action,"unparent")){  Unparent=1; }
+    if(strSame(keep,"false")){ KeepTransform=0; }
+
+    if(!Unparent){ if(!mo || !mo->Flags&TNS_OBJECT_FLAGS_SELECTED) return LA_FINISHED; 
+        if(!la_ParentableRecursive(root,mo)) laEnableMessagePanel(0,0,"It didn't work","There are loops in parenting",e->x,e->y,0,e); return LA_FINISHED;
+    }
+
+    if(keep){
+        la_MakeParentExecuteRecursive(root,mo,Unparent,KeepTransform);
+        laRecordInstanceDifferences(&T->World, "tns_world"); laPushDifferences(Unparent?"Unparent":"Parent", TNS_HINT_TRANSFORM);
+        return LA_FINISHED;
+    }
+    laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e);
+    return LA_RUNNING;
+}
+void laui_MakeParent(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
+    laColumn* c=laFirstColumn(uil);
+    laShowItemFull(uil,c,pp,"_this_M_make_parent",0,"action=parent;keep_transform=true;text=Keep transform",0,0);
+    laShowItemFull(uil,c,pp,"_this_M_make_parent",0,"action=parent;keep_transform=false;text=Directly",0,0);
+}
+void laui_Unparent(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
+    laColumn* c=laFirstColumn(uil);
+    laShowItemFull(uil,c,pp,"_this_M_unparent",0,"action=unparent;keep_transform=true;text=Keep transform",0,0);
+    laShowItemFull(uil,c,pp,"_this_M_unparent",0,"action=unparent;keep_transform=false;text=Directly",0,0);
+}
+
+int la_ClearTransformationRecursive(tnsObject* root, int global,int location,int rotation,int scale){
+    int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){
+        tnsObject* o=lip->p; if(!o->Flags&TNS_OBJECT_FLAGS_SELECTED) continue;
+        if(location){
+            if(global){ o->GLocation[0]=o->GLocation[1]=o->GLocation[2]=0;}
+            else{ o->Location[0]=o->Location[1]=o->Location[2]=0; }
+        }
+        if(rotation){
+            if(global){ o->GRotation[0]=o->GRotation[1]=o->GRotation[2]=0;}
+            else{ o->Rotation[0]=o->Rotation[1]=o->Rotation[2]=0; }
+        }
+        if(scale){ if(global){ o->GScale=1;} else{ o->Scale=1; } }
+        if(global) tnsGlobalTransformValueChanged(o); else tnsSelfTransformValueChanged(o);
+        laRecordInstanceDifferences(o, "tns_object"); any++;
+        any+=la_ClearTransformationRecursive(o,global,location,rotation,scale);
+    } return any;
+}
+int OPINV_ClearTransformation(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+
+    int global=0,location=0,rotation=0,scale=0;
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"global"),"true")){ global=1; }
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"location"),"true")){ location=1; }
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"rotation"),"true")){ rotation=1; }
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"scale"),"true")){ scale=1; }
+
+    int any=0;
+    if(location||rotation||scale){
+        any=la_ClearTransformationRecursive(root,global,location,rotation,scale);
+        if(any){ laPushDifferences("Clear Transformations", TNS_HINT_TRANSFORM); laNotifyUsers("tns.world"); }
+    }
+
+    return LA_FINISHED;
+}
+
+
+STRUCTURE(MEDupVert){
+    int oi; tnsMVert* nmv; tnsMVert* omv; int IsBorder;
+};
+STRUCTURE(MEDupEdge){
+    int oi; tnsMEdge* nme; tnsMEdge* ome; int IsBorder; 
+};
+STRUCTURE(MEDupFace){
+    int oi; tnsMFace* nmf; tnsMFace* omf;
+};
+STRUCTURE(MExtrudeExtra){
+    MEDupVert* dv; int nextv,maxv;
+    MEDupEdge* de; int nexte,maxe;
+    MEDupFace* df; int nextf,maxf;
+    tnsMeshObject* mo;
+    int RemoveOriginalFaces;
+};
+
+int la_IsSelectionBorderVertex(tnsMVert* mv){
+    if(!mv->elink.pFirst)
+        return 0;
+    int NearSelected=0, NearUnselected=0;
+    for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
+        tnsMEdge* me=lip->p; if(!(me->fl&&me->fr)) return 1;
+        tnsMVert* av=tnsMMeshEdgeAnotherVert(me,mv);
+        if(me->fl->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { return 1; }
+        if(me->fr->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { return 1; }
+        if(NearUnselected && NearSelected) return 1;
+    }
+    return 0;
+}
+int la_IsSelectionBorderEdge(tnsMEdge* me){
+    if(me->fl&&me->fr){ 
+        if ((me->fl->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fr->flags&TNS_MESH_FLAG_SELECTED))||
+            (me->fr->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fl->flags&TNS_MESH_FLAG_SELECTED))) return 1;
+        else return (me->fr->flags==me->fl->flags&&me->fl->flags==0);
+    } return 1;
+}
+MExtrudeExtra* la_InitExtrude(tnsMeshObject* mo){
+    MExtrudeExtra* ee=memAcquireSimple(sizeof(MExtrudeExtra));
+    arrEnsureLength(&ee->dv, ee->nextv, &ee->maxv, sizeof(MEDupVert));
+    arrEnsureLength(&ee->de, ee->nexte, &ee->maxe, sizeof(MEDupEdge));
+    arrEnsureLength(&ee->df, ee->nextf, &ee->maxf, sizeof(MEDupFace));
+    ee->mo=mo;
+    return ee;
+}
+void la_ExtrudeMakeDuplication(MExtrudeExtra* ee){
+    tnsMeshObject* mo=ee->mo;
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
+        arrEnsureLength(&ee->dv, ee->nextv, &ee->maxv, sizeof(MEDupVert));
+        MEDupVert* dv=&ee->dv[ee->nextv];
+        tnsMVert* nmv=tnsMMeshNewVert(mo); tnsVectorCopy3d(mv->p, &nmv->p); dv->oi=mv->i; mv->i=ee->nextv; dv->nmv=nmv; dv->omv=mv;
+        dv->IsBorder=la_IsSelectionBorderVertex(mv);
+        ee->nextv++;
+    }
+    for(tnsMEdge* me=mo->me.pFirst;me;me=me->Item.pNext){ if(!(me->flags&TNS_MESH_FLAG_SELECTED)) continue;
+        arrEnsureLength(&ee->de, ee->nexte, &ee->maxe, sizeof(MEDupEdge));
+        MEDupEdge* de=&ee->de[ee->nexte];
+        tnsMEdge* nme=tnsMMeshNewEdge(mo); de->oi=me->i; me->i=ee->nexte; de->nme=nme; de->ome=me; de->IsBorder=la_IsSelectionBorderEdge(me);
+        tnsMMeshEdgeAssignVerts(nme, ee->dv[me->vl->i].nmv, ee->dv[me->vr->i].nmv);
+        if(me->fl&&me->fr){ ee->RemoveOriginalFaces=1; }
+        ee->nexte++;
+    }
+    for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
+        if(!(mf->flags&TNS_MESH_FLAG_SELECTED)) continue;
+        arrEnsureLength(&ee->df, ee->nextf, &ee->maxf, sizeof(MEDupFace));
+        MEDupFace* df=&ee->df[ee->nextf];
+        tnsMFace* nmf=tnsMMeshNewFace(mo); df->oi=mf->i; mf->i=ee->nextf; df->nmf=nmf; df->omf=mf;
+        for(laListItemPointer*lip=mf->l.pFirst;lip;lip=lip->pNext){
+            tnsMEdge* ome=lip->p; tnsMMeshFaceAddEdge(nmf,ee->de[ome->i].nme);
+        }
+        ee->nextf++;
+    }
+    for(int i=0;i<ee->nextv;i++){ ee->dv[i].omv->i=ee->dv[i].oi; ee->dv[i].omv->flags&=(~TNS_MESH_FLAG_SELECTED); ee->dv[i].nmv->flags|=TNS_MESH_FLAG_SELECTED; }
+    for(int i=0;i<ee->nexte;i++){ ee->de[i].ome->i=ee->de[i].oi; ee->de[i].ome->flags&=(~TNS_MESH_FLAG_SELECTED); ee->de[i].nme->flags|=TNS_MESH_FLAG_SELECTED; }
+    for(int i=0;i<ee->nextf;i++){
+        ee->df[i].omf->i=ee->df[i].oi;
+        ee->df[i].omf->flags&=(~TNS_MESH_FLAG_SELECTED);
+        ee->df[i].nmf->flags|=TNS_MESH_FLAG_SELECTED; }
+}
+void la_ReconnectFaces(MExtrudeExtra* ee){
+    tnsMeshObject* mo=ee->mo;
+    if(ee->RemoveOriginalFaces){
+        for(int i=0;i<ee->nextf;i++){ tnsMMeshRemoveFaceOnly(mo, ee->df[i].omf); }
+        for(int i=0;i<ee->nexte;i++){ if(ee->de[i].IsBorder) continue; tnsMMeshRemoveEdgeFace(mo, ee->de[i].ome); }
+        for(int i=0;i<ee->nextv;i++){ if(ee->dv[i].IsBorder) continue; tnsMMeshRemoveVertEdgeFace(mo, ee->dv[i].omv); }
+    }
+    for(int i=0;i<ee->nexte;i++){ 
+        if(!ee->de[i].IsBorder) continue; MEDupEdge*de=&ee->de[i];
+        tnsMMeshMakeFace4v(mo, de->ome->vl, de->ome->vr, de->nme->vr, de->nme->vl);
+    }
+}
+void la_FinishExtrude(MExtrudeExtra* ee){
+    tnsMMeshRefreshIndex(ee->mo);
+    tnsInvaliateMeshBatch(ee->mo);
+    laRecordInstanceDifferences(ee->mo, "tns_mesh_object"); laPushDifferences("Extruded", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
+    free(ee->dv); free(ee->de); free(ee->df); memFree(ee);
+}
+int OPINV_Extrude(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject; if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE) return 0;
+
+    if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
+
+    MExtrudeExtra* ee=la_InitExtrude(mo);
+
+    la_ExtrudeMakeDuplication(ee);
+    
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"duplicate_only"), "true")){
+        la_FinishExtrude(ee);
+        if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB)) return LA_RUNNING; return LA_FINISHED;
+    }
+
+    la_ReconnectFaces(ee);
+
+    la_FinishExtrude(ee);
+    if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB)) return LA_RUNNING; return LA_FINISHED;
+
+    return LA_FINISHED;
+}
+
+int la_EdgeShouldDeleteVert(tnsMVert* mv){
+    if(!mv->elink.pFirst) return 0;
+    int NearSelected=0, NearUnselected=0;
+    for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
+        tnsMEdge* me=lip->p;
+        tnsMVert* av=tnsMMeshEdgeAnotherVert(me,mv);
+        if(av->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { NearUnselected=1; }
+        if(NearUnselected && NearSelected) return 1;
+    }
+    return 0;
+}
+int la_FaceShouldDeleteVert(tnsMVert* mv){
+    if(!mv->elink.pFirst) return 0;
+    int NearSelected=0, NearUnselected=0, IsBorder=0;
+    for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){
+        tnsMEdge* me=lip->p;
+        if(!(me->fl&&me->fr)){ IsBorder=1; }
+        if(me->fl){ if(me->fl->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { NearUnselected=1; } }
+        if(me->fr){ if(me->fr->flags&TNS_MESH_FLAG_SELECTED){ NearSelected=1; } else { NearUnselected=1; } }
+        if(NearUnselected && NearSelected) return 0;
+    }
+    if((!NearUnselected) && IsBorder) return 1;
+    return 1;
+}
+int la_FaceShouldDeleteEdge(tnsMEdge* me){
+    if(me->fl&&me->fr){ 
+        if ((me->fl->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fr->flags&TNS_MESH_FLAG_SELECTED))||
+            (me->fr->flags&TNS_MESH_FLAG_SELECTED) && (!(me->fl->flags&TNS_MESH_FLAG_SELECTED))) return 0;
+        else return (me->fr->flags==me->fl->flags&&me->fl->flags==1);
+    }else{
+        if(me->fl&&me->fl->flags&TNS_MESH_FLAG_SELECTED&&!me->fr) return 1;
+        if(me->fr&&me->fr->flags&TNS_MESH_FLAG_SELECTED&&!me->fl) return 1;
+    } return 0;
+}
+void la_DeleteVertices(tnsMeshObject* mo){
+    tnsMVert* nextmv; for(tnsMVert*mv=mo->mv.pFirst;mv;mv=nextmv){ nextmv=mv->Item.pNext; if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
+        tnsMMeshRemoveVertEdgeFace(mo, mv);
+    }
+}
+void la_DeleteEdges(tnsMeshObject* mo){
+    laListHandle lv={0};
+    for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
+        if(la_EdgeShouldDeleteVert(mv)) lstAppendPointer(&lv,mv);
+    }
+    tnsMEdge* nextme; for(tnsMEdge*me=mo->me.pFirst;me;me=nextme){ nextme=me->Item.pNext; if(!(me->flags&TNS_MESH_FLAG_SELECTED)) continue;
+        tnsMMeshRemoveEdgeFace(mo, me);
+    }
+    tnsMVert* mv; while(mv=lstPopPointer(&lv)){ tnsMMeshRemoveVertEdgeFace(mo,mv); }
+}
+void la_DeleteFaces(tnsMeshObject* mo, int OnlyFaces){
+    laListHandle lv={0}, le={0};
+    if(OnlyFaces){
+        tnsMFace* nextmf; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=nextmf){ nextmf=mf->Item.pNext; if(!(mf->flags&TNS_MESH_FLAG_SELECTED)) continue;
+            tnsMMeshRemoveFaceOnly(mo, mf);
+        }
+    }else{
+        for(tnsMVert*mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ if(!(mv->flags&TNS_MESH_FLAG_SELECTED)) continue;
+            if(la_FaceShouldDeleteVert(mv)) lstAppendPointer(&lv,mv);
+        }
+        for(tnsMEdge*me=mo->me.pFirst;me;me=me->Item.pNext){ if(!(me->flags&TNS_MESH_FLAG_SELECTED)) continue;
+            if(la_FaceShouldDeleteEdge(me)) lstAppendPointer(&le,me);
+        }
+        tnsMFace* nextmf; for(tnsMFace*mf=mo->mf.pFirst;mf;mf=nextmf){ nextmf=mf->Item.pNext; if(!(mf->flags&TNS_MESH_FLAG_SELECTED)) continue;
+            tnsMMeshRemoveFaceOnly(mo, mf);
+        }
+        tnsMEdge* me; while(me=lstPopPointer(&le)){ tnsMMeshRemoveEdgeFace(mo,me); }
+        tnsMVert* mv; while(mv=lstPopPointer(&lv)){ tnsMMeshRemoveVertEdgeFace(mo,mv); }
+    }
+}
+int la_DeleteSelectedObjectsRecursive(tnsObject* root){
+    int any=0; for(laListItemPointer* lip=root->ChildObjects.pFirst;lip;lip=lip->pNext){ if(!lip->p) continue;
+        tnsObject* o=lip->p; la_DeleteSelectedObjectsRecursive(lip->p);
+        if(o->Flags&TNS_OBJECT_FLAGS_SELECTED){ tnsDestroyObject(o); any++; }
+    }
+    return any;
+}
+int OPINV_Delete(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance){ return 0; }
+    laCanvasExtra* ex=a->This->EndInstance; tnsCamera*c=ex->ViewingCamera; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    tnsMeshObject* mo=ex->ActiveObject;
+    
+    if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){
+        if(la_DeleteSelectedObjectsRecursive(root)){
+            laRecordInstanceDifferences(&T->World, "tns_world"); laPushDifferences("Deleted objects", TNS_HINT_TRANSFORM); laNotifyUsers("tns.world");
+        }
+    }else{
+        if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
+        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"vertices")){
+            la_DeleteVertices(mo);
+        }elif(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"edges")){
+            la_DeleteEdges(mo);
+        }elif(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"faces")){
+            la_DeleteFaces(mo,0);
+        }elif(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"only_faces")){
+            la_DeleteFaces(mo,1);
+        }else{
+            laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e);
+            return LA_RUNNING;
+        }
+        tnsMMeshDeselectAll(mo);
+        tnsMMeshRefreshIndex(mo);
+        tnsInvaliateMeshBatch(mo);
+        laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Deleted primitives", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
+    }
+
+    return LA_FINISHED;
+}
+void laui_Delete(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
+    laColumn* c=laFirstColumn(uil);
+    laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=vertices;text=Vertices",0,0);
+    laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=edges;text=Edges",0,0);
+    laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=faces;text=Faces",0,0);
+    laShowItemFull(uil,c,pp,"_this_M_delete",0,"mode=only_faces;text=Only Faces",0,0);
+}
+
+void la_RegisterModellingOperators(){
+    laPropContainer *pc; laProp *p;
+    laOperatorType *at;
+    laEnumProp *ep;
+
+    laCreateOperatorType("M_toggle_edit_mode", "Toggle Edit Mode", "Toggle edit mode of the active object", OPCHK_ThereIsActiveObject, 0, 0, OPINV_ToggleEdit, 0, 0, 0);
+    laCreateOperatorType("M_select", "Select", "Select things in the viewport", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Select, OPMOD_Select, 0, LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("M_grab", "Grab", "Grab things and move around", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Grab, OPMOD_Transformation, 0, LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("M_scale", "Scale", "Scale selected things", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Scale, OPMOD_Transformation, 0, LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("M_rotate", "Rotate", "Rotation selected things", OPCHK_ViewportAndSceneExists, 0, 0, OPINV_Rotate, OPMOD_Transformation, 0, LA_EXTRA_TO_PANEL);
+    at=laCreateOperatorType("M_make_parent", "Make Parent", "Parent objects to active objects or unparent selected ones", 0, 0, 0, OPINV_MakeParent, OPMOD_FinishOnData, 0, 0);
+    at->UiDefine = laui_MakeParent;
+    at=laCreateOperatorType("M_unparent", "Unparent", "Unparent selected objects", 0, 0, 0, OPINV_MakeParent, OPMOD_FinishOnData, 0, 0);
+    at->UiDefine = laui_Unparent;
+    laCreateOperatorType("M_clear_transformations", "Clear Transformations", "Clear transformations in objects", 0, 0, 0, OPINV_ClearTransformation, 0, 0, 0);
+    laCreateOperatorType("M_extrude", "Extrude", "Extrude parts of the mesh", 0, 0, 0, OPINV_Extrude, OPMOD_Transformation, 0, 0);
+    at=laCreateOperatorType("M_delete", "Delete", "Delete parts of the mesh", 0, 0, 0, OPINV_Delete, OPMOD_FinishOnData, 0, 0);
+    at->UiDefine=laui_Delete;
+
+}

+ 2011 - 0
source/lagui/resources/la_operators.c

@@ -0,0 +1,2011 @@
+#include "../la_5.h"
+
+extern LA MAIN;
+extern struct _tnsMain *T;
+
+void la_PanelActiviatorParser(laStringSplitor *ss, uint32_t *IconID, char *DisplayString){
+    char *StrArg;
+    if (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"));
+    }
+}
+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);
+        }
+        if (StrArg = strGetArgumentString(ss, "icon")){
+            int adv=0; *IconID = laToUnicode(StrArg, &adv);
+        }
+    }
+}
+
+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);
+
+int OPMOD_FinishOnData(laOperator* a, laEvent* e){
+    if(a->ConfirmData){
+        return LA_FINISHED_PASS;
+    }
+    return LA_RUNNING;
+}
+int OPCHK_AlwaysTrue(laPropPack *pp, laStringSplitor *ss){
+    return 1;
+}
+
+int OPINV_DoNothing(laOperator *a, laEvent *e){
+    return LA_FINISHED;
+}
+int OPINV_PureYesNo(laOperator *a, laEvent *e){
+    laEnableYesNoPanel(a, 0, "Please Consider:", "Are You Sure?", 80, 80, 250, e);
+    return LA_FINISHED;
+}
+
+#define DEFINE_FORMAT(str, type) \
+    if (!strcmp(format, str))    \
+        return type;
+int la_DetectFileItemType(laFileItem *fi){
+    char *format = strGetLastSegment(fi->Name, '.');
+
+    DEFINE_FORMAT("udf", LA_FILETYPE_UDF);
+    DEFINE_FORMAT("lasdexchange", LA_FILETYPE_LASDEXCHANGE);
+
+    DEFINE_FORMAT("odt", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("ods", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("odp", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("txt", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("c", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("cpp", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("cxx", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("cs", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("pas", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("h", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("hpp", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("hxx", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("inl", LA_FILETYPE_DOCUMENT);
+
+    DEFINE_FORMAT("doc", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("docx", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("xls", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("xlsx", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("ppt", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("pptx", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("rtf", LA_FILETYPE_DOCUMENT);
+    DEFINE_FORMAT("md", LA_FILETYPE_DOCUMENT);
+
+    DEFINE_FORMAT("jpg", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("jpeg", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("png", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("tga", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("bmp", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("exr", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("psd", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("kra", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("dng", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("cr2", LA_FILETYPE_IMAGE);
+    DEFINE_FORMAT("dds", LA_FILETYPE_IMAGE);
+
+    DEFINE_FORMAT("mp3", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("wav", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("ape", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("flac", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("cue", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("wma", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("aac", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("m4a", LA_FILETYPE_AUDIO);
+    DEFINE_FORMAT("ogg", LA_FILETYPE_AUDIO);
+
+    DEFINE_FORMAT("mp4", LA_FILETYPE_VIDEO);
+    DEFINE_FORMAT("mov", LA_FILETYPE_VIDEO);
+    DEFINE_FORMAT("avi", LA_FILETYPE_VIDEO);
+    DEFINE_FORMAT("avchd", LA_FILETYPE_VIDEO);
+    DEFINE_FORMAT("mkv", LA_FILETYPE_VIDEO);
+    DEFINE_FORMAT("qt", LA_FILETYPE_VIDEO);
+    DEFINE_FORMAT("flv", LA_FILETYPE_VIDEO);
+
+    DEFINE_FORMAT("zip", LA_FILETYPE_COMPRESSED);
+    DEFINE_FORMAT("rar", LA_FILETYPE_COMPRESSED);
+    DEFINE_FORMAT("gz", LA_FILETYPE_COMPRESSED);
+    DEFINE_FORMAT("bz", LA_FILETYPE_COMPRESSED);
+    DEFINE_FORMAT("7z", LA_FILETYPE_COMPRESSED);
+    DEFINE_FORMAT("iso", LA_FILETYPE_COMPRESSED);
+    DEFINE_FORMAT("dmg", LA_FILETYPE_COMPRESSED);
+
+    DEFINE_FORMAT("ttf", LA_FILETYPE_FONT);
+    DEFINE_FORMAT("otf", LA_FILETYPE_FONT);
+    DEFINE_FORMAT("woff", LA_FILETYPE_FONT);
+
+    DEFINE_FORMAT("svg", LA_FILETYPE_VECTOR);
+    DEFINE_FORMAT("dwg", LA_FILETYPE_VECTOR);
+    DEFINE_FORMAT("dxf", LA_FILETYPE_VECTOR);
+    DEFINE_FORMAT("cdr", LA_FILETYPE_VECTOR);
+
+    DEFINE_FORMAT("htm", LA_FILETYPE_WEBPAGE);
+    DEFINE_FORMAT("html", LA_FILETYPE_WEBPAGE);
+    DEFINE_FORMAT("xhtml", LA_FILETYPE_WEBPAGE);
+
+    DEFINE_FORMAT("xml", LA_FILETYPE_META);
+    DEFINE_FORMAT("dat", LA_FILETYPE_META);
+    DEFINE_FORMAT("json", LA_FILETYPE_META);
+
+    DEFINE_FORMAT("blend", LA_FILETYPE_BLEND);
+
+    DEFINE_FORMAT("pdf", LA_FILETYPE_PDF);
+
+    DEFINE_FORMAT("exe", LA_FILETYPE_EXEC);
+
+    DEFINE_FORMAT("dll", LA_FILETYPE_SYS);
+    DEFINE_FORMAT("sys", LA_FILETYPE_SYS);
+
+    return 0;
+}
+void la_FileBrowserRebuildList(laFileBrowser *fb){
+    laFileItem *fi = 0;
+    laDiskItem *dl = 0;
+    laListHandle Files = {0};
+    char Lookup[2048]={0};
+    char Final[2048]={0};
+    char DiskLabels[256] = {0};
+    char *pd = DiskLabels;
+    int len = strlen(fb->Path);
+    int NumDisks = 0;
+    long long FreeAvailable = 0;
+    long long FreeSpace_UNUSED = 0;
+    long long TotalSpace = 0;
+    real Ratio = 0;
+
+    if (fb->Path[len - 1] != L'/') strcat(fb->Path, "/");
+    
+    struct dirent **NameList;
+    int NumFiles=scandir(fb->Path,&NameList,0,alphasort);
+
+    while (fi = lstPopItem(&fb->FileList))
+        memFree(fi);
+
+    for(int i=0;i<NumFiles;i++){
+        struct dirent* d = NameList[i];
+        if(!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")){continue;}
+        struct stat s;
+        sprintf(Final, "%s%s",fb->Path,d->d_name);
+        stat(Final, &s);
+        if (S_ISDIR(s.st_mode)){
+            fi = memAcquireSimple(sizeof(laFileItem));
+            strcpy(fi->Name, d->d_name);
+            fi->IsFolder = 1;
+            fi->Type = LA_FILETYPE_FOLDER;
+            lstAppendItem(&fb->FileList, fi);
+        }elif (!fb->SelectFolder){
+            fi = memAcquireSimple(sizeof(laFileItem));
+            strcpy(fi->Name, d->d_name);
+            fi->Size = s.st_size;
+            fi->Type = la_DetectFileItemType(fi);
+
+            struct tm *t = localtime(&s.st_ctime);
+            fi->TimeModified.Year = t->tm_year+1900;
+            fi->TimeModified.Month = t->tm_mon+1;;
+            fi->TimeModified.Day = t->tm_mday;
+            fi->TimeModified.Hour = t->tm_hour;
+            fi->TimeModified.Minute = t->tm_min;
+            fi->TimeModified.Second = t->tm_sec;
+
+            lstAppendItem(&Files, fi);
+            //lstAppendItem(&fb->FileList, fi);
+        }
+    }
+
+    lstCombineLists(&fb->FileList, &Files);
+    
+    for (int i=0;i<NumFiles;i++){ free(NameList[i]); }
+    free(NameList);
+
+    while (dl = lstPopItem(&fb->Disks))
+        memFree(dl);
+
+    //NumDisks = GetLogicalDriveStrings(256, DiskLabels) / 4;
+
+    //while (*pd)
+    //{
+    //    char Name[3] = "*:";
+    //    Name[0] = *pd;
+    //    if (GetDiskFreeSpaceEx(Name, &FreeAvailable, &TotalSpace, &FreeSpace_UNUSED))
+    //    {
+    //        dl = memAcquireSimple(sizeof(laDiskItem));
+    //        dl->ID = *pd;
+    //        dl->Total_GB = (real)TotalSpace / 1073741824.0f;   //B->GB
+    //        dl->Free_GB = (real)FreeAvailable / 1073741824.0f; //B->GB
+
+    //        if (Name[0] == fb->Path[0])
+    //            fb->RootDisk = dl;
+
+    //        lstAppendItem(&fb->Disks, dl);
+    //    }
+    //    pd += 4;
+    //}
+
+    fb->Active = 0;
+
+    fb->FileName[0] = 0;
+}
+laFileBrowser *la_FileBrowserInit(laOperator *a){
+    laFileBrowser *fb = memAcquireHyper(sizeof(laFileBrowser));
+
+    strcpy(fb->Path, MAIN.WorkingDirectory->Ptr);
+
+    if (strArgumentMatch(a->ExtraInstructionsP, "select", "folder")){
+        fb->SelectFolder = LA_FILE_SELECT_FOLDER;
+    }
+
+    la_FileBrowserRebuildList(fb);
+
+    return fb;
+}
+void laset_FileBrowserSelectFile(laFileBrowser *fb, laFileItem *fi, int State){
+    int len;
+    if (fb->Active == fi){
+        if (fi->IsFolder){
+            len = strlen(fb->Path);
+            if (fb->Path[len - 1] != L'/') strcat(fb->Path, "/");
+            strcat(fb->Path, fi->Name);
+            la_FileBrowserRebuildList(fb);
+            laRecalcCurrentPanelImmediate();
+        }
+    }else{
+        if (!fi->IsFolder){
+            strCopyFull(fb->FileName, fi->Name);
+        }
+        fb->Active = fi;
+    }
+}
+int la_FileBrowserConfirm(laOperator *a, laFileBrowser *fb){
+    char buf[2048] = {0};
+    int plen;
+    if (!fb->SelectFolder && fb->FileName[0] == L'\0') return 0;
+    plen = strlen(fb->Path);
+    if (fb->Path[plen - 1] != L'/') strcat(fb->Path, "/");
+    strCopyFull(buf, fb->Path);
+    strcat(buf, fb->FileName);
+    laConfirmString(a, buf, LA_CONFIRM_OK);
+    return 1;
+}
+void *laget_FileBrowserFirstFile(laFileBrowser *fb, void* unused){
+    return fb->FileList.pFirst;
+}
+void *laget_FileBrowserActiveFile(laFileBrowser *fb){
+    return fb->Active;
+}
+void laget_FileBrowserDiskID(laDiskItem *di, char *result){
+    result[0] = di->ID;
+    result[1] = L':';
+    result[2] = L'/';
+    result[3] = L'\0';
+}
+void *laset_FileBrowserActiveDisk(laFileBrowser *fb, laDiskItem *di, int UNUSED_State){
+    fb->RootDisk = di;
+    laget_FileBrowserDiskID(di, fb->Path);
+    la_FileBrowserRebuildList(fb);
+}
+void laset_FileBrowserPath(laFileBrowser *fb, char *content){
+    strCopyFull(fb->Path, content);
+    la_FileBrowserRebuildList(fb);
+    laRecalcCurrentPanel();
+}
+void la_FileBrowserUpLevel(laFileBrowser *fb){
+    char *p = fb->Path;
+    char *LastP = 0;
+    int Count = 0;
+    for (p; *p; p++){
+        if (*p && *p == L'/' && p[1]!=0){
+            LastP = p;
+            Count++;
+        }
+    }
+    if (Count > 1) *LastP = 0;
+    else if(LastP) *(LastP + 1) = 0;
+    la_FileBrowserRebuildList(fb);
+}
+int OPINV_FileBrowser(laOperator *a, laEvent *e){
+    a->CustomData = la_FileBrowserInit(a);
+    laEnableOperatorPanel(a, 0, LA_RH2, LA_RH2, 500, 500, 0, 0, 0, 0, LA_RH2, LA_RH2, LA_RH2, LA_RH2, e);
+    return LA_RUNNING;
+}
+int OPEXT_FileBrowser(laOperator *a, int mark){
+    memFree(a->CustomData);
+
+    return 0;
+}
+int OPMOD_FileBrowser(laOperator *a, laEvent *e){
+    laFileBrowser *fb = a->CustomData;
+
+    if (a->ConfirmData){
+        if (a->ConfirmData->Mode == LA_CONFIRM_CANCEL){
+            laConfirmSameDataIfAny(a);
+            return LA_FINISHED_PASS;
+        }
+        if (a->ConfirmData->Mode == LA_CONFIRM_OK){
+            if (la_FileBrowserConfirm(a, fb)){
+                //MessageBox(0, a->NextConfirmData->StrData, "!", 0);
+            }
+            return LA_FINISHED_PASS;
+        }
+    }
+
+    if (e->Type == LA_ESCAPE_DOWN){
+        laConfirmInt(a, 0, LA_CONFIRM_CANCEL);
+        return LA_FINISHED;
+    }
+
+    return LA_RUNNING;
+}
+int OPCHK_IsFileBrowser(laPropPack *This, laStringSplitor *ss){
+    if (This && This->LastPs->p->SubProp == _LA_PROP_FILE_BROWSER) return 1;
+    return 0;
+}
+int OPINV_FileBrowserUpLevel(laOperator *a, laEvent *e){
+    if (a->This){
+        la_FileBrowserUpLevel(a->This->LastPs->UseInstance);
+        laNotifyUsersPPPath(a->This, "path");
+        laRecalcCurrentPanel();
+    }
+    return LA_FINISHED_PASS;
+}
+
+int OPEXT_UDFOperation(laOperator *a, laEvent *e){
+    laUDFPreviewExtra *upe = a->CustomData;
+    laUDFContentNode *ucni, *NextUCNI;
+    for (ucni = upe->ContentNodes.pFirst; ucni; ucni = NextUCNI){
+        NextUCNI = ucni->Item.pNext;
+        la_FreePropStepCache(ucni->PP.Go);
+        la_DestroyUDFContentNodeTreeRecursive(ucni, 1);
+    }
+    memFree(upe);
+}
+int OPINV_UDFAppend(laOperator *a, laEvent *e){
+    laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
+    a->CustomData = memAcquireSimple(sizeof(laUDFPreviewExtra));
+    return LA_RUNNING;
+}
+int OPMOD_UDFAppend(laOperator *a, laEvent *e){
+    laUDFPreviewExtra *upe = a->CustomData;
+    //if (upe->UDF){
+    //    if (!a->OperatorPanel){
+    //        printf("Execute!\n");
+    //        laExtractUDFContent(upe->UDF, 0, &upe->ContentNodes);
+    //        laCloseUDF(upe->UDF);
+    //        return LA_FINISHED;
+    //    }
+    //    return LA_RUNNING;
+    //}
+    if (a->ConfirmData){
+        if (a->ConfirmData->StrData){
+            laManagedUDF* m;
+            upe->UDF = laOpenUDF(a->ConfirmData->StrData, 1, 0, &m);
+            if (upe->UDF){
+                laExtractUDF(upe->UDF, m, 0, 0);
+                //laExtractUDFContent(upe->UDF, 0, &upe->ContentNodes);
+                //laEnableOperatorPanel(a, 0, 30, 100, 500, 500, 10000, 10000, 300, 200, 20, 20, 30, 20, e);
+                laCloseUDF(upe->UDF);
+                laRecordEverythingAndPush();
+                return LA_FINISHED;
+            }
+        }
+        return LA_FINISHED;
+    }
+
+    return LA_RUNNING;
+}
+void la_DestroyUDFContentNodeTreeRecursive(laUDFContentNode *ucn, int FreeRoot);
+int OPINV_UDFSaveInstance(laOperator *a, laEvent *e){
+    laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
+    a->CustomData = memAcquireSimple(sizeof(laUDFPreviewExtra));
+    return LA_RUNNING;
+}
+int OPMOD_UDFSaveInstance(laOperator *a, laEvent *e){
+    laUDFPreviewExtra *upe = a->CustomData;
+    laPropPack* pp=a->This; if(!pp||!pp->EndInstance) return LA_CANCELED;
+    if (a->ConfirmData){
+        if (a->ConfirmData->StrData){
+            upe->UDF = laPrepareUDF(a->ConfirmData->StrData);
+            if (upe->UDF){
+                laWritePropP(upe->UDF, pp);
+                laPackUDF(upe->UDF, 0);
+                return LA_FINISHED;
+            }
+        }
+    }
+
+    return LA_FINISHED;
+}
+
+void* laget_FirstManagedUDF(void* unused, void* unused_pi){ return MAIN.ManagedUDFs.pFirst; }
+
+void laset_ManagedSavePage(laManagedSaveExtra* mse, int p){
+    mse->ShowPage=p;
+    laRegisterModifications(0,0,0,0);
+}
+
+int OPEXT_ManagedSave(laOperator *a, laEvent *e){
+    laManagedSaveExtra *upe = a->CustomData;
+    memFree(upe);
+}
+int OPINV_ManagedSave(laOperator *a, laEvent *e){
+    int OnExit=0;
+    if(a->ExtraInstructionsP){
+        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "quiet"),"true")){
+            int empty=0; laRegisterModifications(0,1,&empty,0);
+            if(strSame(strGetArgumentString(a->ExtraInstructionsP, "ignore_unassigned"),"true")) empty=0;
+            if(!empty){ laSaveManagedUDF(); return LA_FINISHED; }
+        }
+        if(strSame(strGetArgumentString(a->ExtraInstructionsP, "on_exit"),"true")){ OnExit=1; }
+    }
+
+    if(laOperatorExistsT(a->Type)) return LA_CANCELED;
+
+    a->CustomData = memAcquire(sizeof(laManagedSaveExtra));
+    laManagedSaveExtra* mse=a->CustomData;
+    mse->OnExit=OnExit;
+    mse->ShowPage = MAIN.ManagerDefaultView;
+    
+    laEnableOperatorPanel(a, 0, LA_RH2,LA_RH2,400,400,0,0,0,0,LA_RH2,LA_RH2,LA_RH2,LA_RH2,e);
+    return LA_RUNNING;
+}
+int OPMOD_ManagedSave(laOperator *a, laEvent *e){
+    laUDFPreviewExtra *upe = a->CustomData;
+
+    if (a->ConfirmData){
+        if(a->ConfirmData->Mode==LA_CONFIRM_CUSTOM_STRING && strSame(a->ConfirmData->StrData,"DISCARD_AND_QUIT")){
+            return LA_OPERATOR_CALLS_SHUTOFF;
+        }
+        if(a->ConfirmData->Mode==LA_CONFIRM_CANCEL||a->ConfirmData->Mode==LA_CONFIRM_OK) return LA_FINISHED;
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING;
+}
+
+int OPINV_ManagedSaveNewFile(laOperator *a, laEvent *e){
+    a->CustomData = memAcquireSimple(sizeof(laUDFPreviewExtra));
+    laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
+    return LA_RUNNING;
+}
+int OPMOD_ManagedSaveNewFile(laOperator *a, laEvent *e){
+    laUDFPreviewExtra *upe = a->CustomData;
+
+    if (a->ConfirmData){
+        if(a->ConfirmData->Mode==LA_CONFIRM_CANCEL){ return LA_FINISHED; }
+        if(a->ConfirmData->Mode==LA_CONFIRM_OK){
+            if(a->ConfirmData->StrData){
+                char* path=a->ConfirmData->StrData;
+                if(la_FindManagedUDF(path)){
+                    laEnableMessagePanel(a, 0, "Duplicated files", "The file you chose already exists in the managed file list.",e->x,e->y,0,e);
+                    return LA_FINISHED;
+                }
+                laManagedUDF* m=MAIN.DummyManageUDF;
+                m->udf = laPrepareUDF(path); strSafeSet(&m->BaseName, strGetLastSegment(path,'/'));
+                m->udf->Managed=1;
+                la_MakeDummyManagedUDF();
+                laNotifyUsers("la.managed_udfs"); laNotifyUsers("la.managed_props");
+            }
+            return LA_FINISHED;
+        }
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING;
+}
+
+int OPINV_UDFManager(laOperator *a, laEvent *e){
+    laRegisterModifications(0,0,0,0);
+    laActivatePanel("LAUI_data_manager", e->x, e->y);
+    return LA_FINISHED;
+}
+
+int OPINV_AddResourceFolder(laOperator *a, laEvent *e){
+    laAddResourceFolder(0);
+    laNotifyUsers("la.user_preferences.resource_folders");
+    return LA_FINISHED;
+}
+int OPINV_RemoveResourceFolder(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->LastPs->UseInstance) return LA_CANCELED;
+    laResourceFolder* rf=a->This->LastPs->UseInstance;
+    laRemoveResourceFolder(rf);
+    laRefreshUDFRegistries();
+    laNotifyUsers("la.user_preferences.resource_folders");
+    return LA_FINISHED;
+}
+
+int OPINV_Undo(laOperator *a, laEvent *e){
+    laUndo();
+    laPrintDBInstInfo();
+    return LA_FINISHED;
+}
+int OPINV_Redo(laOperator *a, laEvent *e){
+    laRedo();
+    laPrintDBInstInfo();
+    return LA_FINISHED;
+}
+
+int OPINV_UDFPropagate(laOperator *a, laEvent *e){
+    laProp* p=a->This?a->This->LastPs->p:0; if(!p||p->PropertyType!=LA_PROP_SUB) return LA_FINISHED;
+    void* instance=a->This->EndInstance; if(!instance) return LA_FINISHED;
+    laPropContainer* pc=la_EnsureSubTarget(p,instance);
+
+    int force=0;
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"force"),"true")){ force=1; }
+
+    laPropagateUDF(pc, instance, force);
+    laNotifyUsers("la.managed_props");
+
+    return LA_FINISHED;
+}
+
+int OPCHK_TerminateProgram(laPropPack *This, laStringSplitor *Instructions){
+    return 1;
+}
+int OPINV_TerminateProgram(laOperator *a, laEvent *e){
+    int empty=0; int mod=laRegisterModifications(1,1,&empty,0);
+    if(mod || empty){ laInvoke(0, "LA_managed_save", 0,0,"on_exit=true;",0); return LA_FINISHED; }
+
+    return LA_OPERATOR_CALLS_SHUTOFF;
+}
+
+int OPCHK_IntSetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_INT)) return 1;
+    else
+        return 0;
+}
+int OPCHK_FloatSetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_FLOAT)) return 1;
+    else
+        return 0;
+}
+int OPCHK_IntArraySetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_INT | LA_PROP_ARRAY)) return 1;
+    else
+        return 0;
+}
+int OPCHK_FloatArraySetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_FLOAT | LA_PROP_ARRAY)) return 1;
+    else
+        return 0;
+}
+int OPCHK_EnumSetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_ENUM)) return 1;
+    else
+        return 0;
+}
+int OPCHK_EnumArraySetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_ENUM | LA_PROP_ARRAY)) return 1;
+    else
+        return 0;
+}
+int OPCHK_StringSetValue(laPropPack *This, laStringSplitor *Instructions){
+    if (This && (This->LastPs->p->PropertyType == LA_PROP_STRING)) return 1;
+    else
+        return 0;
+}
+int OPINV_EnumSetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_ENUM)){
+        laEnumProp *ep = a->This->LastPs->p;
+        laSetEnum(a->This, ep->DefVal);
+    }
+    return LA_FINISHED;
+}
+int OPINV_IntSetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
+        laIntProp *ip = a->This->LastPs->p;
+        laSetInt(a->This, ip->DefVal);
+    }
+    return LA_FINISHED;
+}
+int OPINV_FloatSetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
+        laFloatProp *ip = a->This->LastPs->p;
+        laSetFloat(a->This, ip->DefVal);
+    }
+    return LA_FINISHED;
+}
+int OPINV_IntSetMax(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
+        laIntProp *ip = a->This->LastPs->p;
+        laSetInt(a->This, ip->Max);
+    }
+    return LA_FINISHED;
+}
+int OPINV_FloatSetMax(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
+        laFloatProp *ip = a->This->LastPs->p;
+        laSetFloat(a->This, ip->Max);
+    }
+    return LA_FINISHED;
+}
+int OPINV_IntSetMin(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
+        laIntProp *ip = a->This->LastPs->p;
+        laSetInt(a->This, ip->Min);
+    }
+    return LA_FINISHED;
+}
+int OPINV_FloatSetMin(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
+        laFloatProp *ip = a->This->LastPs->p;
+        laSetFloat(a->This, ip->Min);
+    }
+    return LA_FINISHED;
+}
+int OPINV_EnumArraySetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_ENUM)){
+        laEnumProp *ep = a->This->LastPs->p;
+        laSetEnumArrayAll(a->This, ep->DefVal);
+    }
+    return LA_FINISHED;
+}
+int OPINV_IntArraySetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
+        laIntProp *ip = a->This->LastPs->p;
+        if (ip->DefArr) laSetIntArrayAllArray(a->This, ip->DefArr);
+        else
+            laSetIntArrayAll(a->This, ip->DefVal);
+    }
+    return LA_FINISHED;
+}
+int OPINV_FloatArraySetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
+        laFloatProp *ip = a->This->LastPs->p;
+        if (ip->DefArr) laSetFloatArrayAllArray(a->This, ip->DefArr);
+        else
+            laSetFloatArrayAll(a->This, ip->DefVal);
+    }
+    return LA_FINISHED;
+}
+int OPINV_IntArraySetMax(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
+        laIntProp *ip = a->This->LastPs->p;
+        laSetIntArrayAll(a->This, ip->Max);
+    }
+    return LA_FINISHED;
+}
+int OPINV_FloatArraySetMax(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
+        laFloatProp *ip = a->This->LastPs->p;
+        laSetFloatArrayAll(a->This, ip->Max);
+    }
+    return LA_FINISHED;
+}
+int OPINV_IntArraySetMin(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_INT)){
+        laIntProp *ip = a->This->LastPs->p;
+        laSetIntArrayAll(a->This, ip->Min);
+    }
+    return LA_FINISHED;
+}
+int OPINV_FloatArraySetMin(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_FLOAT)){
+        laFloatProp *ip = a->This->LastPs->p;
+        laSetFloatArrayAll(a->This, ip->Min);
+    }
+    return LA_FINISHED;
+}
+int OPINV_StringSetDefault(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_STRING)){
+        laStringProp *sp = a->This->LastPs->p;
+        if (sp->DefStr) laSetString(a->This, sp->DefStr);
+        else
+            laSetString(a->This, "");
+    }
+    return LA_FINISHED;
+}
+
+int OPINV_StringGetFolderPath(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_STRING)){
+
+        laInvoke(a, "LA_file_dialog", e, 0, "select=folder;", 0);
+
+        return LA_RUNNING;
+    }
+    return LA_FINISHED;
+}
+int OPINV_StringGetFilePath(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_STRING)){
+
+        laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
+
+        return LA_RUNNING;
+    }
+    return LA_FINISHED;
+}
+int OPMOD_StringGetFolderOrFilePath(laOperator *a, laEvent *e){
+    if (a->ConfirmData){
+        if (a->ConfirmData->StrData){
+            laStringProp *sp = a->This->LastPs->p;
+
+            laSetString(a->This, a->ConfirmData->StrData);
+
+            return LA_FINISHED_PASS;
+        }
+        return LA_FINISHED_PASS;
+    }
+    return LA_RUNNING;
+}
+
+int OPINV_StringCopy(laOperator *a, laEvent *e){
+    laPropPack* pp=a->This; if(!a->This) return LA_FINISHED;
+
+    char _buf[256]={0}; char* buf=_buf;
+    laGetString(pp,_buf,&buf);
+    laCopyToClipboard(buf);
+
+    return LA_FINISHED;
+}
+int OPINV_StringPaste(laOperator *a, laEvent *e){
+    if (a->This && (a->This->LastPs->p->PropertyType & LA_PROP_STRING)){
+        laStringProp *sp = a->This->LastPs->p;
+        if (sp->DefStr) laSetString(a->This, sp->DefStr);
+        else laSetString(a->This, "");
+    }
+    return LA_FINISHED;
+}
+
+int OPCHK_SubPutDataBlock(laPropPack *This, laStringSplitor *Instructions){
+    //laListItem* Inst;
+    //void* Actuall=0;
+    //laProp* p;
+    //if (!MAIN.RestoreInstance || !This || !Instructions) return 0;
+    //p = la_PropLookup(&This->LastPs->p->SubProp->Props, strGetArgumentString(Instructions, "identifier"));
+    //if (!p) return 0;
+    //for (Inst = &p->SubProp->TrashBin.pFirst; Inst; Inst = Inst->pNext) {
+    //	if (Inst == MAIN.RestoreInstance) {
+    //		Actuall = Inst; break;
+    //	}
+    //}
+    //if(!Actuall)
+    //	for (Inst = &p->SubProp->FailedNodes.pFirst; Inst; Inst = Inst->pNext) {
+    //		if (Inst == MAIN.RestoreInstance) {
+    //			Actuall = Inst; break;
+    //		}
+    //	}
+    //if (!Actuall) return 0;
+
+    return 0;
+}
+int OPINV_SubPutDataBlock(laOperator *a, laEvent *e){
+    //laProp* p = la_PropLookup(&a->This->LastPs->p->SubProp->Props, strGetArgumentString(a->ExtraInstructionsP, "identifier"));
+
+    //lstRemoveItem(&p->SubProp->TrashBin, MAIN.RestoreInstance);
+    //lstRemoveItem(&p->SubProp->FailedNodes, MAIN.RestoreInstance);
+
+    ////laNotifySubPropUsers(p->SubProp, MAIN.RestoreInstance);
+
+    //laAppendInstance(p, a->This->EndInstance, MAIN.RestoreInstance);
+
+    //laNotifySubPropUsers(p, a->This->EndInstance);
+    //laNotifySubPropUsers(_LA_PROP_TRASH_ITEM, p->SubProp);
+    //laNotifySubPropUsers(_LA_PROP_FAILED_ITEM, p->SubProp);
+
+    return LA_FINISHED;
+}
+int OPCHK_SubRestoreDataBlock(laPropPack *This, laStringSplitor *Instructions){
+    if (This) return 1;
+    return 0;
+}
+int OPINV_SubRestoreDataBlock(laOperator *a, laEvent *e){
+    //if (a->This->EndInstance) {
+    //	MAIN.RestoreInstance = a->This->EndInstance;
+    //}
+
+    //laEnableOperatorPanel(a, 0, e->x, e->y, 600, 600, 2000, 1000, 100, 100, 0, 0, 0, 0, e);
+
+    return LA_FINISHED; //will directly finish after actuator panel close or any feedback event and don't pass any feedback.
+}
+int OPEXT_SubRestoreDataBlock(laOperator *a, int unused){
+    return 0;
+}
+
+int OPCHK_CombineChildBlocks(laPropPack *This, laStringSplitor *Instructions){
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laBlock *b = l->OnBlockSeperator;
+    if (!(b)) return 0;
+}
+int OPINV_CombineChildBlocks(laOperator *a, laEvent *e){
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laBlock *b = l->OnBlockSeperator;
+    if (!b) b = laDetectBlockRecursive(l->FirstBlock, e->x, e->y);
+    if (b){
+        laCombineChildBlocks(b);
+        return LA_FINISHED;
+    }
+    return LA_CANCELED;
+}
+
+STRUCTURE(laNewPanelData){
+    laUiTemplate* SelectedTemplate;
+    laBlock* b;
+};
+
+void laui_TitleOnly(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context){
+    laColumn *col = Extra, *c, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiItem *ui;
+
+    c = laFirstColumn(uil);
+
+    laShowItemFull(uil, c, This, "title", LA_WIDGET_STRING_PLAIN, 0, 0, 0);
+}
+laUiTemplate* laget_FirstPanelTemplate(void* unused1, void* unused2){
+    return MAIN.PanelTemplates.pFirst;
+}
+void laset_NewPanelSetTemplate(laNewPanelData *np, laUiTemplate *uit, int State){
+    np->SelectedTemplate = uit;
+}
+int laget_NewPanelGetActiveTemplate(laNewPanelData* np, laUiTemplate* uit){
+    return np->SelectedTemplate;
+}
+void laui_PanelTemplateSelect(laUiList *uil, laPropPack *This, laPropPack *OperatorProps, laColumn *UNUSED, int context){
+    laColumn *c;
+    laProp *p, *gp;
+
+    c = laFirstColumn(uil);
+
+    gp = OperatorProps->LastPs->p;
+    
+    laShowItem(uil, c, OperatorProps, "template");
+}
+
+int OPINV_NewLayout(laOperator *a, laEvent *e){
+    laWindow* w=MAIN.CurrentWindow;
+    laDesignLayout(w, "New Layout");
+    laRedrawCurrentWindow();
+    return LA_FINISHED;
+}
+int OPINV_NewPanel(laOperator *a, laEvent *e){
+    laNewPanelData* np= CreateNew(laNewPanelData);
+    a->CustomData = np;
+    laEnableOperatorPanel(a, 0, e->x-50,e->y-50,500,500,1000,0,0,0,0,0,0,0,e);
+    return LA_RUNNING;
+}
+int OPMOD_NewPanel(laOperator *a, laEvent *e){
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laNewPanelData* np=a->CustomData;
+
+    if(!a->ConfirmData) return LA_RUNNING;
+
+    if(a->ConfirmData->Mode == LA_CONFIRM_CANCEL||a->ConfirmData->Mode == LA_CONFIRM_OK) return LA_CANCELED;
+
+    if(a->ConfirmData->Mode == LA_CONFIRM_DATA){
+        if (!np || !np->SelectedTemplate) return LA_CANCELED;
+        laPanel *p = la_FindFreePanelByTemplate(MAIN.CurrentWindow, np->SelectedTemplate);
+        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);
+        return LA_FINISHED;
+    }
+
+    return LA_RUNNING;
+}
+int OPINV_BlockFoldTitle(laOperator *a, laEvent *e){
+    laBlock* b=a->This?a->This->EndInstance:0;
+    if(!b) return LA_CANCELED;
+
+    if(strSame(strGetArgumentString(a->ExtraInstructionsP, "show"), "true")) laUnfoldBlockTitle(b);
+    else laFoldBlockTitle(b);
+    
+    return LA_FINISHED;
+}
+int OPINV_BlockMaximize(laOperator *a, laEvent *e){
+    laBlock* b=a->This?a->This->EndInstance:0;
+
+    if(!b || strSame(strGetArgumentString(a->ExtraInstructionsP, "restore"), "true")) laRestoreToLayout();
+    else laMaximizeBlock(b);
+    
+    return LA_FINISHED;
+}
+int OPINV_CanvasUiMaximize(laOperator *a, laEvent *e){
+    laUiItem* ui=a->This?a->This->EndInstance:0;
+    laPanel* p=MAIN.CurrentPanel;
+
+    if(!ui || !p || (!ui->Type->Tag&LA_UI_TAG_IS_OFFSCREEN) || MAIN.CurrentWindow->MaximizedUi ||
+        strSame(strGetArgumentString(a->ExtraInstructionsP, "restore"), "true")) laRestoreCanvasUI();
+    else laMaximizeCanvasUI(ui,p);
+    
+    return LA_FINISHED;
+}
+int OPINV_HideMenuBar(laOperator *a, laEvent *e){
+    if(!MAIN.CurrentWindow->MaximizedUi || strSame(strGetArgumentString(a->ExtraInstructionsP, "restore"), "true")) laShowMenuBar();
+    else laHideMenuBar();
+    
+    return LA_FINISHED;
+}
+int OPINV_BlockTearOffPanel(laOperator *a, laEvent *e){
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laBlock* b = l->OperatingBlock;
+    if (!b) b = laDetectBlockRecursive(l->FirstBlock, e->x, e->y);
+    if(!b) return LA_CANCELED;
+    
+    laTearOffPanel(b,0);
+    
+    return LA_FINISHED;
+}
+int OPCHK_BlockHasMorePanels(laPropPack *This, laStringSplitor *Instructions){
+    laPanel*p = This?This->LastPs->UseInstance:0;
+    if(p && p->Mode == LA_PANEL_FLOATING_TOP) return 1;
+
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laBlock *b = l->OperatingBlock;
+    if (b->Panels.pFirst == b->Panels.pLast) return 0;
+    return 1;
+}
+int OPINV_BlockClosePanel(laOperator *a, laEvent *e){
+    laPanel*p = a->This?a->This->LastPs->UseInstance:0;
+    if(p && p->Mode == LA_PANEL_FLOATING_TOP){
+        laDestroySinglePanel(p);
+        return LA_FINISHED;
+    }
+
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laBlock *b = l->OperatingBlock;
+    int x = e->x, y = e->y;
+    if (!b) b = laDetectBlockRecursive(l->FirstBlock, e->x, e->y);
+    if (b){
+        if (b->CurrentPanel){
+            //laLocalToWindow(a, MAIN.CurrentPanel, &x, &y);
+            laEnableYesNoPanel(a, 0, "Caution!", "Are you sure to destroy this panel?", e->x - 250, e->y, 250, e);
+            return LA_RUNNING;
+        }
+    }
+    return LA_CANCELED;
+}
+int OPMOD_BlockClosePanel(laOperator *a, laEvent *e){
+    laLayout *l = MAIN.CurrentWindow->CurrentLayout;
+    laBlock *b = l->OperatingBlock;
+    if (e->Type == LA_ESCAPE_DOWN) return LA_FINISHED;
+    if (a->ConfirmData){
+        if (!b) b = laDetectBlockRecursive(l->FirstBlock, e->x, e->y);
+        if (!b) return LA_CANCELED;
+        if (a->ConfirmData->Mode == LA_CONFIRM_OK){
+            laDestroySinglePanel(b->CurrentPanel);
+            la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+        }
+        return LA_FINISHED;
+    }else
+        return LA_RUNNING;
+}
+int laui_BlockEdgeMenu(laOperator *WindowAct, laLayout *l, laBlock *b, laEvent *e){
+    laPanel *p;
+    laColumn *c, *cl, *cr;
+    laUiList *uil;
+    p = laDefineAndEnableMenuPanel(0, WindowAct, 0, e->x, e->y, 500, 200, e);
+    uil = laPrepareUi(p);
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.5);
+    cl = laLeftColumn(c, 0);
+    cr = laRightColumn(c, 0);
+
+    laShowItem(uil, c, 0, "LA_combine_child_blocks");
+
+    laEnclosePanelContent(p,uil);
+}
+laBlock* la_MakeDropBlock(laBlock* DropToBlock, int DropLocation){
+    switch (DropLocation){
+    case 0: return DropToBlock;
+    case LA_BLOCK_DROP_LOCATION_U:
+        laSplitBlockVertical(DropToBlock, 0.5); laSwapSubBlocks(DropToBlock);
+        return DropToBlock->B1;
+    case LA_BLOCK_DROP_LOCATION_B:
+        laSplitBlockVertical(DropToBlock, 0.5);
+        return DropToBlock->B2;
+    case LA_BLOCK_DROP_LOCATION_L:
+        laSplitBlockHorizon(DropToBlock, 0.5); laSwapSubBlocks(DropToBlock);
+        return DropToBlock->B1;
+    case LA_BLOCK_DROP_LOCATION_R:
+        laSplitBlockHorizon(DropToBlock, 0.5);
+        return DropToBlock->B2;
+    }
+}
+void la_StartDocking(laWindow* from, laPanel* p){
+    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){  w->DockingFrom = from; w->IsDocking=1; } MAIN.DockingPanel=p;
+}
+void la_StopDocking(){
+    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){  w->DockingFrom = 0; w->IsDocking=0; } MAIN.DockingPanel=0;
+}
+void la_ClearDockingTarget(){
+    for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){  w->CurrentLayout->DropToBlock=0; }
+}
+int OPINV_DockPanel(laOperator* a, laEvent* e){
+    laPanel*p = a->This?a->This->LastPs->UseInstance:0;
+    if(!p) return LA_CANCELED;
+
+    la_StartDocking(MAIN.CurrentWindow, p);
+    laRestoreToLayout();
+    laRestoreCanvasUI();
+
+    return LA_FINISHED;
+}
+int OPINV_NewWindow(laOperator* a, laEvent* e){
+    laWindow* w = a->This?a->This->EndInstance:MAIN.CurrentWindow;
+    
+    laWindow* nw =laDesignWindow(w->X,w->Y,w->CW,w->CH);
+    laLayout* l=(w->Layouts.pFirst!=w->Layouts.pLast)?w->CurrentLayout:0;
+
+    if (l && !strSame(strGetArgumentString(a->ExtraInstructionsP, "clean"), "true")){
+        laLayout* nextl=l->Item.pPrev?l->Item.pPrev:l->Item.pNext;
+        w->CurrentLayout=nextl; lstRemoveItem(&w->Layouts, l); lstAppendItem(&nw->Layouts, l); nw->CurrentLayout=l;
+        laRenameWindow(nw, l->ID->Ptr);
+        laRenameWindow(w, w->CurrentLayout->ID->Ptr);
+    }else{
+        laDesignLayout(nw, "Empty Layout");
+    }
+    laRedrawAllWindows();
+
+    return LA_FINISHED;
+}
+
+void *la_OnBlockSeperator(laBlock *b, laEvent *e){
+    int at;
+    laBlock *bb;
+    if (!b->B1) return 0;
+    if (b->Vertical){
+        at = b->H * b->SplitRatio + b->Y;
+        if (e->x>=b->X && e->x<=b->X+b->W && e->y >= at - LA_SEAM_W && e->y <= at + LA_SEAM_W){
+            return b;
+        }
+    }else{
+        at = b->X + b->W * b->SplitRatio;
+        if (e->y>=b->Y && e->y<=b->Y+b->H && e->x >= at - LA_SEAM_W && e->x <= at + LA_SEAM_W){
+            return b;
+        }
+    }
+    if (bb = la_OnBlockSeperator(b->B1, e)) return bb;
+    else
+        return la_OnBlockSeperator(b->B2, e);
+}
+int la_DetectBlockDropLocation(laBlock *b, int X, int Y){
+    laPanel *p = b->Panels.pFirst;
+    if (!p) return 0;
+
+    real L = tnsGetRatiod(p->X, p->X + p->W, X);
+    real U = tnsGetRatiod(p->Y, p->Y + p->H, Y);
+    if (L > U){
+        if (U < 0.25){
+            if (L < 0.75) return LA_BLOCK_DROP_LOCATION_U;
+            else
+                return LA_BLOCK_DROP_LOCATION_R;
+        }else{
+            if (L < 0.75) return 0;
+            else
+                return LA_BLOCK_DROP_LOCATION_R;
+        }
+    }else{
+        if (U > 0.75){
+            if (L < 0.25) return LA_BLOCK_DROP_LOCATION_L;
+            else
+                return LA_BLOCK_DROP_LOCATION_B;
+        }else{
+            if (L < 0.25) return LA_BLOCK_DROP_LOCATION_L;
+            else
+                return 0;
+        }
+    }
+}
+int laui_BlockMenu(laOperator *WindowAct, laWindow* w, laLayout *l, laBlock *b, laEvent *e){
+    laPanel *p;
+    laColumn *c;
+    laUiList *uil;
+    p = laDefineAndEnableMenuPanel(0, WindowAct, 0, b->X, b->Y + LA_RH + 1, 500, 500, e);
+    uil = laPrepareUi(p);
+    c = laFirstColumn(uil);
+    laPanel* forp=b->CurrentPanel;
+
+    laUiItem* b1=laBeginRow(uil,c,0,0);
+    laShowItem(uil,c,&b->PP,"fold");
+    laUiItem* b2=laOnConditionThat(uil,c,laPropExpression(&w->PP, "maximized_block"));{
+        laShowItemFull(uil,c,&b->PP,"maximize",0,"restore=true;text=Restore;",0,0);
+    }laElse(uil,b2);{
+        laShowItem(uil,c,&b->PP,"maximize");
+    }laEndCondition(uil,b2);
+    laEndRow(uil,b1);
+
+    laShowSeparator(uil,c);
+
+    if(forp->PanelTemplate->Header){
+        laShowLabel(uil, c, "Panel properties:", 0, 0);
+        forp->PanelTemplate->Header(uil, &forp->PP, &forp->PropLinkPP, c, 0);
+    }else{
+        laShowLabel(uil, c, "Panel doesn't have configurable property.", 0, 0);
+    }
+
+    //laShowItem(uil, c, 0, "LA_new_panel");
+    //laShowItem(uil, c, 0, "LA_block_close_panel");
+    //laShowItem(uil, c, 0, "LA_block_tear_off_panel");
+
+    laEnclosePanelContent(p,uil);
+}
+int la_ProcessBlockEvent(laOperator *a, laBlock *b, laEvent *e){
+    int Executed = 0, Ret=1;
+    int L = LA_RH+LA_SEAM_W, R, tw = 0;
+    real ratio = 1.0f;
+    laPanel *p = b->Panels.pFirst;
+    laGeneralUiExtraData *uid = a->CustomData;
+    laLayout *l;
+    if(!b->Panels.pFirst){return 0;}
+    if (laIsInBlockHeader(b, e->x, e->y) || MAIN.CurrentWindow->CurrentLayout->ClickedPanel){
+        MAIN.CurrentWindow->CurrentLayout->OperatingBlock = b;
+
+        if (b->CurrentPanel){
+            if (e->Type == LA_MOUSE_WHEEL_DOWN && b->CurrentPanel->Item.pNext){
+                b->CurrentPanel = b->CurrentPanel->Item.pNext;
+                Executed = 1;
+            }elif (e->Type == LA_MOUSE_WHEEL_UP && b->CurrentPanel->Item.pPrev){
+                b->CurrentPanel = b->CurrentPanel->Item.pPrev;
+                Executed = 1;
+            }
+        }
+
+        if(!b->Folded){
+            for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+                tw += (p->TitleWidth + LA_SEAM_W*2);
+            }
+            if (tw > b->W - LA_SEAM_W*2 - LA_RH) ratio = (real)(b->W - LA_SEAM_W*2 - LA_RH) / tw;
+
+            if ((e->Type == LA_L_MOUSE_DOWN)){
+                uid->LastX = e->x;
+                uid->LastY = e->y;
+                int LT=0,RT=0;
+                for (p = b->Panels.pFirst; p; p = p->Item.pNext){
+                    RT = LT + p->TitleWidth+LA_SEAM_W*2;
+                    if (e->x >= b->X + L+LT * ratio && e->x < b->X + L+RT * ratio){
+                        MAIN.CurrentWindow->CurrentLayout->ClickedPanel = p;
+                        b->CurrentPanel = p;
+                        Executed = 1;
+                    }
+                    LT = RT;
+                }
+            }elif (e->Type == LA_MOUSEMOVE){
+                if (abs(e->x - uid->LastX) > 30 || abs(e->y - uid->LastY) > 30){
+                    if (MAIN.CurrentWindow->CurrentLayout->ClickedPanel){
+                        l = MAIN.CurrentWindow->CurrentLayout;
+                        l->DropToBlock = b;
+                        l->DropLocation = la_DetectBlockDropLocation(b, e->x, e->y);
+                    }
+                }
+            }elif (e->Type == LA_L_MOUSE_UP){
+                l = MAIN.CurrentWindow->CurrentLayout;
+                if (l->DropToBlock){
+                    l->DropToBlock = la_MakeDropBlock(l->DropToBlock,l->DropLocation);
+                    p = l->ClickedPanel;
+                    if(p->Block == l->DropToBlock){
+                        if(laTearOffPanel(p->Block, p)) Executed=1;
+                    }else{
+                        p->Block->CurrentPanel = p->Item.pPrev ? p->Item.pPrev : (p->Item.pNext ? p->Item.pNext : 0);
+                        lstRemoveItem(&p->Block->Panels, p); laBlock* orig_block=p->Block->parent;
+                        int clear=0; if(!lstHaveItemInList(&p->Block->Panels)){clear=1;}
+                        lstPushItem(&l->DropToBlock->Panels, p);
+                        p->Block = l->DropToBlock;
+                        if(clear){
+                            laCombineChildBlocks(orig_block);
+                            if(!lstFindItem(orig_block->CurrentPanel,nutSameAddress,&orig_block->Panels)){
+                                orig_block->CurrentPanel = orig_block->Panels.pFirst;
+                            }
+                        }
+                        p->Block->CurrentPanel = p;
+                        Executed = 1;
+                        la_RecalcBlockRecursive(p->Block, p->Block->X, p->Block->Y, p->Block->W, p->Block->H);
+                        if(orig_block!=p->Block){
+                            la_RecalcBlockRecursive(orig_block, orig_block->X, orig_block->Y, orig_block->W, orig_block->H);
+                        }
+                    }
+                }
+                MAIN.CurrentWindow->CurrentLayout->DropToBlock = 0;
+                MAIN.CurrentWindow->CurrentLayout->ClickedPanel = 0;
+                return 0;
+            }
+        }else{
+            b->OnButton=1;Ret=0;
+            if(laIsInBlockBotton1(b, e->x, e->y)){ b->OnButton=2; if(e->Type==LA_L_MOUSE_DOWN){laUnfoldBlockTitle(b);Executed=1;Ret=1;} }
+            elif(laIsInBlockBotton2(b, e->x, e->y)){ b->OnButton=2; if(e->Type==LA_L_MOUSE_DOWN){laMaximizeBlock(b);Executed=1;Ret=1;} }
+        }
+
+        if (Executed){
+            b->CurrentPanel->Refresh |= LA_TAG_RECALC;
+            la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H);
+        }
+
+        if (!Executed && e->Type == LA_L_MOUSE_DOWN && laIsInBlockBotton1(b, e->x, e->y)){
+            laui_BlockMenu(a, MAIN.CurrentWindow, MAIN.CurrentWindow->CurrentLayout, b, e);
+        }
+        return Ret;
+    }else{
+        b->OnButton=0;
+    }
+    return 0;
+}
+int la_ProcessBlockEdgeEvent(laOperator *WindowAct, laLayout *l, laBlock *b, laEvent *e){
+    laBlock *ob = l->MovingBlock;
+    laWindow *w = WindowAct->Instance;
+    if (e->Type == LA_MOUSEMOVE && ob && l->MovingBlock && l->IsMoving){
+        if (ob->Vertical) ob->SplitRatio = (real)(e->y - ob->Y) / (real)(ob->H);
+        else
+            ob->SplitRatio = (real)(e->x - ob->X) / (real)(ob->W);
+        la_RecalcBlockRecursive(ob, ob->X, ob->Y, ob->W, ob->H);
+        if (ob->B1->CurrentPanel) ob->B1->CurrentPanel->Refresh |= LA_TAG_RECALC;
+        if (ob->B2->CurrentPanel) ob->B2->CurrentPanel->Refresh |= LA_TAG_RECALC;
+        return 1;
+    }
+    if (ob = la_OnBlockSeperator(b, e)){
+        ob->B1->OnButton=ob->B2->OnButton=0;
+        l->MovingBlock = ob;
+        if (e->Type == LA_L_MOUSE_DOWN){
+            l->IsMoving = 1;
+        }elif (e->Type == LA_L_MOUSE_UP){
+            l->IsMoving = 0;
+        }elif (e->Type == LA_R_MOUSE_DOWN){
+            l->OnBlockSeperator = ob;
+            laui_BlockEdgeMenu(WindowAct, l, ob, e);
+        }
+        return 1;
+    }
+    l->MovingBlock = 0;
+    return 0;
+}
+
+real la_ScrollerVerticalPan(int MousePanY, laPanel *p, laUiList *suil, laUiItem *pui){
+    int DisplayH, TotalH;
+
+    if (!pui){ DisplayH = p->H-suil->U; }
+    else{ DisplayH = pui->Page?(pui->B-pui->Page->U):(pui->B - pui->U); }
+
+    TotalH = suil->B - suil->U;
+
+    return ((real)TotalH * (real)MousePanY / (real)DisplayH);
+}
+real la_ScrollerHorizontalPan(int MousePanX, laPanel *p, laUiList *suil, laUiItem *pui){
+    int DisplayW, TotalW;
+
+    DisplayW = pui->Page?(pui->R-pui->Page->L):(pui->R - pui->L);
+    TotalW = suil->R - suil->L;
+
+    return ((real)TotalW * (real)MousePanX / (real)DisplayW);
+}
+
+void laui_LayoutCycle(laUiList *uil, laPropPack *This, laPropPack *OperatorProps, laColumn *UNUSED, int context){
+    laColumn *c;
+    laProp *p, *gp;
+
+    c = laFirstColumn(uil);
+    
+    laShowItemFull(uil, c, 0, "la.windows.layouts", 0, 0, laui_IdentifierOnly, 0);
+    laShowItem(uil, c, 0, "LA_new_layout");
+}
+int OPINV_SwitchLayout(laOperator *a, laEvent *e){
+    laWindow *w = MAIN.CurrentWindow; if (!w) return LA_FINISHED;
+
+    if (strSame(strGetArgumentString(a->ExtraInstructionsP, "show_list"), "true")){
+        laPanel* p =laEnableOperatorPanel(a, 0, e->x-LA_RH, e->y-LA_RH, 500, 500, 0,0,0,0,0,0,0,0,e);
+        return LA_RUNNING;
+    }
+
+    if (strSame(strGetArgumentString(a->ExtraInstructionsP, "reverse"), "true")) w->CurrentLayout = w->CurrentLayout->Item.pPrev ? w->CurrentLayout->Item.pPrev : w->Layouts.pLast;
+    else w->CurrentLayout = w->CurrentLayout->Item.pNext ? w->CurrentLayout->Item.pNext : w->Layouts.pFirst;
+
+    laRenameWindow(w, w->CurrentLayout->ID->Ptr);
+
+    la_StopAllOperators();
+    laRetriggerOperators();
+
+    laNotifyUsers("la.windows.layouts");
+
+    return LA_FINISHED;
+}
+
+int OPINV_DeleteTheme(laOperator *a, laEvent *e){
+    laTheme* t = a->This?a->This->EndInstance:MAIN.CurrentTheme;
+    if(!t || MAIN.Themes.pFirst == MAIN.Themes.pLast) return LA_CANCELED;
+
+    laBoxedTheme* NextBt;
+    for(laBoxedTheme* bt=t->BoxedThemes.pFirst; bt; bt=NextBt){
+        NextBt = bt->Item.pNext; lstRemoveItem(&t->BoxedThemes, bt); memFree(bt);
+    }
+    lstRemoveItem(&MAIN.Themes, t); memFree(t);
+    if(t==MAIN.CurrentTheme){MAIN.CurrentTheme = MAIN.Themes.pFirst;la_RefreshThemeColor(MAIN.CurrentTheme);}
+    laNotifyUsers("themes"); laRedrawCurrentWindow();
+    return LA_FINISHED;
+}
+
+int la_GenericTopPanelProcessing(laOperator* a, laEvent* e){
+    laPanel* p;
+    if (p = laDetectPanel(e->x, e->y)){
+        int x = e->x;
+        int y = e->y;
+        laWindowToLocal(0, p, &x, &y);
+        if (laIsInPanel(p, x, y) /*&& p->Show*/){
+            laSetOperatorLocalizer(p);
+            laInvokeUi(a, "LA_panel_operator", e, p, 0, 1);
+            return LA_RUNNING;
+        }
+    }
+    return 0;
+}
+int la_GeneratePasteEvent(laWindow* w){
+    XConvertSelection(MAIN.dpy, MAIN.bufid, MAIN.fmtid, MAIN.propid, w->win, CurrentTime);
+}
+int OPINV_SystemPaste(laOperator *a, laEvent *e){ la_GeneratePasteEvent(MAIN.CurrentWindow); return LA_FINISHED; }
+int OPINV_Window(laOperator *a, laEvent *e){
+    laRetriggerOperators();
+    return LA_RUNNING;
+}
+int OPMOD_Window(laOperator *a, laEvent *e){
+    laPanel *p;
+    laBlock *b = 0;
+    laWindow *w = a->Instance;
+    laGeneralUiExtraData *uid = a->CustomData;
+
+    if (!uid) uid = memAcquireSimple(sizeof(laGeneralUiExtraData));
+    a->CustomData = uid;
+
+    if(laKeyMapExecuteEvent(a, &MAIN.KeyMap, e)) return LA_RUNNING_PASS;
+
+    if(w->IsDocking && MAIN.DockingPanel){
+        laRestoreToLayout();
+        laRestoreCanvasUI();
+        laLayout* l=MAIN.CurrentWindow->CurrentLayout;
+        laBlock *Recieve = laDetectBlockRecursive(l->FirstBlock, e->x, e->y);
+        if (Recieve){
+            la_ClearDockingTarget(); l->DropToBlock = Recieve;
+            l->DropLocation = la_DetectBlockDropLocation(Recieve, e->x, e->y);
+        }else{
+            MAIN.CurrentWindow->CurrentLayout->DropToBlock = 0;
+        }
+
+        if(e->Type==LA_L_MOUSE_UP && l->DropToBlock){
+            l->DropToBlock = la_MakeDropBlock(l->DropToBlock, l->DropLocation);
+            laDockPanel(w->DockingFrom, l->DropToBlock, MAIN.DockingPanel);
+            la_StopDocking();la_ClearDockingTarget(); return LA_RUNNING;
+        }
+
+        if(e->Type==LA_R_MOUSE_DOWN || (e->Type==LA_KEY_DOWN&&e->key==LA_KEY_ESCAPE)){
+            la_StopDocking();la_ClearDockingTarget(); return LA_RUNNING;
+        }
+        return LA_RUNNING;
+    }
+
+    if(w->MaximizedUi && w->MaximizedUiPanel){
+        if(((e->y<LA_RH && e->x<LA_RH)||e->y<LA_SEAM_W) && uid->Dragging){ laShowMenuBar(); uid->Dragging=0; }
+        if(!la_UiOperatorExists(w->MaximizedUi)){
+            laSetOperatorLocalizer(0);
+            laInvokeUi(a, w->MaximizedUi->Type->OperatorID, e, w->MaximizedUi, 0, 1);
+            return LA_RUNNING;
+        }
+        if(e->y>LA_2RH && e->x>LA_2RH){ if(!uid->Dragging)laRequestDelayEvent(0.5); uid->Dragging=1; }
+        if(e->Type==LA_TIME_DELAY){
+            laHideMenuBar(); }
+    }else{
+
+        laBlock* RootBlock=w->MaximizedBlock?w->MaximizedBlock:w->CurrentLayout->FirstBlock;
+        if (la_ProcessBlockEdgeEvent(a, w->CurrentLayout, RootBlock, e)) return LA_RUNNING;
+
+        b = w->MaximizedBlock?w->MaximizedBlock:laDetectBlockRecursive(w->CurrentLayout->FirstBlock, e->x, e->y);
+        if (b && la_ProcessBlockEvent(a, b, e)) return LA_RUNNING;
+        
+        for (p = w->Panels.pFirst; p; p = p->Item.pNext){
+            int x = e->x;
+            int y = e->y;
+            laWindowToLocal(0, p, &x, &y);
+            if (laIsInPanel(p, x, y) && p->Show){
+                laSetOperatorLocalizer(p);
+                if (!p->LaterDestroy) laInvokeUi(a, "LA_panel_operator", e, p, 0, 1);
+                return LA_RUNNING;
+            }
+        }
+    }
+    
+    if(la_GenericTopPanelProcessing(a,e)) return LA_RUNNING;
+
+    return LA_RUNNING;
+}
+int OPINV_Panel(laOperator *a, laEvent *e){
+    if (!((laPanel *)a->Instance)->Show) return LA_FINISHED;
+
+    a->CustomData = memAcquireSimple(sizeof(laGeneralUiExtraData));
+    laRetriggerOperators();
+    return LA_RUNNING;
+}
+int OPEXT_Panel(laOperator *a, int ExitCode){
+    memFree(a->CustomData);
+    return 0;
+}
+int la_ScrollPanel(laGeneralUiExtraData*ex, laPanel*p, laEvent* e){
+    int ret=0;
+    if(ex->TargetIndexVali==4 && e->Type==LA_MOUSEMOVE){
+        laUiList* uuil=ex->Ptr1; laUiItem* upui=ex->Ptr2;
+        if(upui){ laPanUiListFree(uuil, ex->LastX-e->x, ex->LastY-e->y);
+            //if(uuil->HeightCoeff){
+                if(uuil->B-upui->Page->PanY<upui->TB-(*p->BT)->BM-LA_SCROLL_W){
+                    upui->Page->PanY = (uuil->B-upui->TB+(*p->BT)->BM+LA_SCROLL_W);
+                    if(upui->Page->PanY<0){upui->Page->PanY=0;}
+                }
+            //}
+        }
+        ex->LastX=e->x; ex->LastY=e->y;
+        laRedrawCurrentPanel();
+        ret= 1;
+    }
+    if(ex->TargetIndexVali==5 && e->Type==LA_MOUSEMOVE){
+        laUiList* uuil=ex->Ptr1; laUiItem* upui=ex->Ptr2;
+        if(upui)laScaleUiList(uuil, -(ex->LastY-e->y)*0.005+1, upui->L, upui->R, upui->U, upui->B);
+        ex->LastX=e->x; ex->LastY=e->y;
+        laRecalcCurrentPanel();
+        ret= 1;
+    }
+    if(e->Type==LA_M_MOUSE_UP){ ex->TargetIndexVali=0; }
+    if (e->Type & LA_KEY_MOUSE_SCROLL || e->Type==LA_M_MOUSE_DOWN){
+        laUiItem *pui = 0; laListHandle levels={0}; int dir;
+        if (e->Type & LA_STATE_DOWN) dir=1;
+        elif (e->Type & LA_STATE_UP) dir=-1;
+        laUiList *duil = la_DetectUiListRecursiveDeep(p->MenuRefer?p->MenuRefer:&p->UI, e->x, e->y, 10000, &pui, 0, 0, 0, 0, &levels);
+        laUiListRecord* lip=levels.pLast; laUiList* uuil=lip->uil; laUiItem* upui=lip->Item.pPrev?((laUiListRecord*)lip->Item.pPrev)->pui:0; int ran=0;
+        if(e->SpecialKeyBit == LA_KEY_CTRL){
+            if(e->Type==LA_M_MOUSE_DOWN){
+                while (lip && upui && (!uuil->AllowScale)) { lip=lip->Item.pPrev; uuil=lip->uil;  upui=lip->Item.pPrev?((laUiListRecord*)lip->Item.pPrev)->pui:0; } 
+                if(uuil) { ex->TargetIndexVali=5; ex->Ptr1=uuil; ex->Ptr2=upui; ex->LastX=e->x; ex->LastY=e->y; ret= 1;}
+            }else{
+            }
+        }else{
+            if(e->Type==LA_M_MOUSE_DOWN){
+                while (lip && upui && (!uuil->AllowScale)) { lip=lip->Item.pPrev; uuil=lip->uil;  upui=lip->Item.pPrev?((laUiListRecord*)lip->Item.pPrev)->pui:0; } 
+                if(uuil) { ex->TargetIndexVali=4; ex->Ptr1=uuil; ex->Ptr2=upui; ex->LastX=e->x; ex->LastY=e->y; ret= 1;}
+            }else{
+                while (lip && upui){
+                    if(uuil->AllowScale){ if((ran=laScaleUiList(uuil, 1.0f+dir*0.1, upui->L, upui->R, upui->U, upui->B))){ laRecalcCurrentPanel(); break;} }
+                    else{ if((ran=laPanUiListAuto(uuil, 0, dir*MAIN.ScrollingSpeed*LA_RH,
+                                uuil->L, upui->R-(uuil->ScrollerShownV?(LA_SCROLL_W+(*p->BT)->RM):0),
+                                uuil->U, upui->B-(*upui->Type->Theme)->BM-(uuil->ScrollerShownH?(LA_SCROLL_W+(*p->BT)->BM):0)))) break; }
+                    lip=lip->Item.pPrev; uuil=lip->uil;  upui=lip->Item.pPrev?((laUiListRecord*)lip->Item.pPrev)->pui:0; 
+                }
+                if(!ran) laPanUiListAuto(p->MenuRefer?p->MenuRefer:&p->UI, 0, dir*MAIN.ScrollingSpeed*LA_RH, 0, p->W, p->TitleBar.B, p->H-(*p->BT)->BM);
+                laRedrawCurrentPanel();
+                ret= 1;
+            }
+        }
+        while(duil=lstPopPointer(&levels));
+    }
+    return ret;
+}
+int OPMOD_Panel(laOperator *a, laEvent *e){
+    int x = e->x;
+    int y = e->y;
+    laPanel *p = a->Instance, *dp;
+    laUiItem *ui = 0;
+    laGeneralUiExtraData *uid = a->CustomData;
+    laListHandle Locals = {0};
+    int RET=LA_RUNNING|(p->IsMenuPanel?0:LA_PASS_ON);
+
+    if(MAIN.DockingPanel){return LA_FINISHED; }
+
+    if (!p->Show || (!laIsInPanel(p, x, y) && !uid->TargetIndexVali)){
+        return LA_FINISHED;
+    }
+
+    int NoPrimaryUI=(p==MAIN.CurrentWindow->MaximizedUiPanel);
+
+    if(p->PanelTemplate && laKeyMapExecuteEvent(a, &p->PanelTemplate->KeyMap, e)) return RET;
+
+    int IsTop=laIsTopPanel(p);
+    if (!IsTop && !uid->TargetIndexVali){
+        laLocalToWindow(0, p, &x, &y);
+        dp = laDetectPanel(x, y);
+        if (p->Mode && dp != p){
+            return LA_FINISHED;
+        }else if ((e->Type & LA_MOUSEDOWN) == LA_MOUSEDOWN){
+            laPopPanel(p); IsTop=1;
+        }else if(p->Mode) return LA_RUNNING;
+        laWindowToLocal(0, p, &x, &y);
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN && (!NoPrimaryUI) && e->x + e->y < p->W + p->H - LA_SCROLL_W*2){
+        laUiItem *pui = 0; laUiList *suil = 0;laListHandle levels={0};
+        laUiList *duil = la_DetectUiListRecursiveDeep(&p->UI, e->x, e->y, 10000, &pui, &suil, 0, 0, 0, &levels);
+        while(duil=lstPopPointer(&levels));
+        if (suil){
+            uid->Ptr1 = suil; uid->Ptr2 = pui;
+            uid->TargetIndexVali = 3;
+            uid->LastX = e->x; uid->LastY = e->y;
+            uid->On=(!pui || e->x>pui->R-LA_SCROLL_W-2*(*p->BT)->RM)?1:0;
+            return LA_RUNNING;
+        }
+    }
+
+    if(la_ScrollPanel(uid,p,e))return LA_RUNNING;
+
+    if (!p->Mode || (IsTop && !uid->TargetIndexVali)){
+        if(y<p->TitleBar.B){ ui = la_DetectUiItemRecursive(&p->TitleBar, x, y, 10000, &Locals, 0); }
+        elif (!ui && (!NoPrimaryUI)){
+            lstClearPointer(&Locals);
+            ui = la_DetectUiItemRecursive(&p->UI, x, y, 10000, &Locals, 0);
+        }
+    }
+    if (ui && !a->Child && ui->Type->OperatorType && !la_UiOperatorExists(ui)){
+        laSetOperatorLocalizer(p);
+        if (laInvokeUiP(a, ui->Type->OperatorType, e, ui, &Locals, 0) >= 0) laRetriggerOperators();
+        lstClearPointer(&Locals);
+        //return LA_RUNNING;
+    }
+    lstClearPointer(&Locals);
+    
+    if (p->Mode && e->Type&LA_MOUSE_EVENT && !uid->TargetIndexVali){
+        if (!p->IsMenuPanel && e->x + e->y > p->W + p->H - LA_SCROLL_W*2){
+            if(e->Type==LA_L_MOUSE_DOWN){ uid->TargetIndexVali = 2; uid->LastX=e->x;uid->LastY=e->y;}
+            return LA_RUNNING;
+        }else{
+            if(e->Type==LA_L_MOUSE_DOWN){  uid->TargetIndexVali = 1; uid->LastX=e->x;uid->LastY=e->y; return LA_RUNNING; }
+        }
+    }
+
+    if (e->Type == LA_MOUSEMOVE){
+        if (uid->TargetIndexVali == 1){
+            if (!p->SL && !p->SR) p->TX = p->X + e->x - uid->LastX;
+            if (!p->ST && !p->SB) p->TY = p->Y + e->y - uid->LastY;
+            laNotifyUsersPPPath(&p->PP, "position");
+            la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH);
+            laRecalcCurrentPanel();
+            return LA_RUNNING;
+        }elif (uid->TargetIndexVali == 2){
+            p->TW += e->x - uid->LastX; p->TH += e->y - uid->LastY;
+            uid->LastX = e->x; uid->LastY = e->y;
+            p->BoundUi=0;
+            laNotifyUsersPPPath(&p->PP, "size");
+            la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH);
+            laRecalcCurrentPanel();
+            return LA_RUNNING;
+        }elif (uid->TargetIndexVali == 3){
+            laUiList *suil = uid->Ptr1; laUiItem *pui = uid->Ptr2;
+            int IsVertical=uid->On;
+            uid->TargetIndexValf+=IsVertical?la_ScrollerVerticalPan(e->y - uid->LastY, p, uid->Ptr1, uid->Ptr2):
+                                        (pui?la_ScrollerHorizontalPan(e->x - uid->LastX, p, uid->Ptr1, uid->Ptr2):0);
+            uid->Dragging = (int)uid->TargetIndexValf; uid->TargetIndexValf-=uid->Dragging;
+            int pV=uid->Dragging*IsVertical, pH=uid->Dragging*(!IsVertical);
+            if (!pui) laPanUiList(suil, pH, pV,0, p->W, suil->U, p->H-(*p->BT)->BM);
+            else laPanUiList(suil, pH, pV, suil->L, pui->R-(suil->ScrollerShownV?(LA_SCROLL_W+(*p->BT)->RM):0),
+                                           suil->U, pui->B-(*p->BT)->BM-(suil->ScrollerShownH?(LA_SCROLL_W+(*p->BT)->BM):0));
+            uid->LastX = e->x; uid->LastY = e->y;
+            laRedrawCurrentPanel();
+            return LA_RUNNING;
+        }
+    }
+
+    if (e->Type == LA_L_MOUSE_UP){
+        uid->TargetIndexVali = 0;
+        return LA_RUNNING;
+    }
+
+    return RET;
+}
+int OPMOD_MenuPanel(laOperator *a, laEvent *e){
+    int x = e->x;
+    int y = e->y;
+    laPanel *p = a->Instance;
+    laUiItem *ui;
+    laListHandle Locals = {0};
+    laGeneralUiExtraData *uid = a->CustomData;
+
+    if(MAIN.DockingPanel){return LA_FINISHED; }
+
+    int IsClose=laIsCloseToPanel(p,x,y);
+    int IsIn=laIsInPanel(p, x, y);
+
+    if(p->CloseWhenMovedOut && (!IsClose || (!IsIn && e->Type==LA_TIME_IDLE) || e->Type==LA_L_MOUSE_DOWN||e->Type==LA_R_MOUSE_DOWN)){ 
+        la_StopUiOperatorService(p);
+        laDestroySinglePanel(p);
+        return LA_FINISHED_PASS;
+    }
+    if (e->Type == LA_ESCAPE_DOWN || (e->Type == LA_L_MOUSE_DOWN && !IsIn)){
+        laConfirmInt(a, 1, LA_CONFIRM_DATA);
+        la_StopUiOperatorService(p);
+        laDestroySinglePanel(p);
+        return LA_FINISHED_PASS;
+    }
+
+    if(p->PanelTemplate && laKeyMapExecuteEvent(a, &p->PanelTemplate->KeyMap, e)) return LA_RUNNING_PASS;
+
+    if (e->Type == LA_L_MOUSE_DOWN && e->y < p->H - LA_SCROLL_W){
+        laUiItem *pui = 0; laUiList *suil = 0;laListHandle levels={0};
+        laUiList *duil = la_DetectUiListRecursiveDeep(p->MenuRefer?p->MenuRefer:&p->UI, e->x, e->y, 10000, &pui, &suil, 0, 0, 0, &levels);
+        while(duil=lstPopPointer(&levels));
+        if (suil){
+            uid->Ptr1 = suil; uid->Ptr2 = pui;
+            uid->TargetIndexVali = 3;
+            uid->LastX = e->x; uid->LastY = e->y;
+            uid->On=(!pui || e->x>pui->R-LA_SCROLL_W-2*(*p->BT)->RM)?1:0;
+            return LA_RUNNING;
+        }
+    }
+    if (e->Type == LA_L_MOUSE_UP && uid->TargetIndexVali == 3){
+        uid->TargetIndexVali = 0;
+        return LA_RUNNING;
+    }
+
+    if(la_ScrollPanel(uid,p,e))return LA_RUNNING;
+
+    if (e->Type == LA_MOUSEMOVE){
+        if (uid->TargetIndexVali == 3){
+            laUiList *suil = uid->Ptr1; laUiItem *pui = uid->Ptr2;
+            int IsVertical=uid->On;
+            uid->TargetIndexValf+=IsVertical?la_ScrollerVerticalPan(e->y - uid->LastY, p, uid->Ptr1, uid->Ptr2):
+                                        (pui?la_ScrollerHorizontalPan(e->x - uid->LastX, p, uid->Ptr1, uid->Ptr2):0);
+            uid->Dragging = (int)uid->TargetIndexValf; uid->TargetIndexValf-=uid->Dragging;
+            int pV=uid->Dragging*IsVertical, pH=uid->Dragging*(!IsVertical);
+            if (!pui) laPanUiList(suil, pH, pV,0, p->W, suil->U, p->H-(*p->BT)->BM);
+            else laPanUiList(suil, pH, pV, suil->L, pui->R-(suil->ScrollerShownV?(LA_SCROLL_W+(*p->BT)->RM):0),
+                                           suil->U, pui->B-(*p->BT)->BM-(suil->ScrollerShownH?(LA_SCROLL_W+(*p->BT)->BM):0));
+            uid->LastX = e->x; uid->LastY = e->y;
+            laRedrawCurrentPanel();
+            return LA_RUNNING;
+        }
+    }
+
+    ui = la_DetectUiItemRecursive(&p->UI, x, y, 10000, &Locals, 0);
+    if (!ui){
+        lstClearPointer(&Locals);
+        ui = la_DetectUiItemRecursive(p->MenuRefer, x, y, 10000, &Locals, 0);
+    }
+
+    if (ui && !la_UiOperatorExists(ui)){
+        laSetOperatorLocalizer(p);
+        laInvokeUiP(a, ui->Type->OperatorType, e, ui, &Locals, 0);
+    }
+
+    lstClearPointer(&Locals);
+
+    if (a->ConfirmData){
+        laConfirmInt(a, a->ConfirmData->IData, a->ConfirmData->Mode);
+        la_StopUiOperatorService(p);
+        laDestroySinglePanel(p);
+        return LA_FINISHED_PASS;
+    }
+
+    return LA_RUNNING;
+}
+int OPMOD_ModalPanel(laOperator *a, laEvent *e){
+    int x = e->x;
+    int y = e->y;
+    laPanel *p = a->Instance;
+    laUiItem *ui = 0;
+    laListHandle Locals = {0};
+    laGeneralUiExtraData *uid = a->CustomData;
+
+    if(MAIN.DockingPanel){return LA_FINISHED; }
+
+    if (e->Type == LA_KEY_DOWN && e->key==LA_KEY_ESCAPE){
+        laConfirmInt(a, 0, LA_CONFIRM_CANCEL);
+        la_StopUiOperatorService(p);
+        laDestroySinglePanel(p);
+        return LA_FINISHED_PASS;
+    }
+
+    if (a->ConfirmData){
+        laConfirmSameDataIfAny(a);
+        if (a->ConfirmData->Mode == LA_CONFIRM_DATA||a->ConfirmData->Mode==LA_CONFIRM_CUSTOM_STRING){
+             return LA_RUNNING_PASS;
+        }
+        la_StopUiOperatorService(p);
+        laDestroySinglePanel(p);
+        return LA_FINISHED_PASS;
+    }
+
+    if (!laIsInPanel(p, e->x, e->y) && !uid->TargetIndexVali) return LA_RUNNING;
+
+    if(p->PanelTemplate && laKeyMapExecuteEvent(a, &p->PanelTemplate->KeyMap, e)) return LA_RUNNING_PASS;
+
+    if (e->Type == LA_L_MOUSE_DOWN && e->y < p->H -  LA_SCROLL_W){
+        laUiItem *pui = 0; laUiList *suil = 0;laListHandle levels={0};
+        laUiList *duil = la_DetectUiListRecursiveDeep(&p->UI, e->x, e->y, 10000, &pui, &suil, 0, 0, 0, &levels);
+        while(duil=lstPopPointer(&levels));
+        if (suil){
+            uid->Ptr1 = suil; uid->Ptr2 = pui;
+            uid->TargetIndexVali = 3;
+            uid->LastX = e->x; uid->LastY = e->y;
+            uid->On=(!pui || e->x>pui->R-LA_SCROLL_W-2*(*p->BT)->RM)?1:0;
+            return LA_RUNNING;
+        }
+    }
+
+    if(la_ScrollPanel(uid,p,e))return LA_RUNNING;
+
+    if (!uid->TargetIndexVali){
+        ui = la_DetectUiItemRecursive(&p->TitleBar, x, y, 10000, &Locals, 0);
+        if (!ui){
+            lstClearPointer(&Locals);
+            ui = la_DetectUiItemRecursive(&p->UI, x, y, 10000, &Locals, 0);
+        }
+    }
+    if (ui && !a->Child && ui->Type->OperatorType && !la_UiOperatorExists(ui)){
+        laSetOperatorLocalizer(p);
+        laInvokeUiP(a, ui->Type->OperatorType, e, ui, &Locals, 0);
+        return LA_RUNNING;
+    }
+    lstClearPointer(&Locals);
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        uid->LastX = e->x;
+        uid->LastY = e->y;
+        if (e->x + e->y > p->W + p->H -  LA_SCROLL_W*2) uid->TargetIndexVali = 2;
+        else
+            uid->TargetIndexVali = 1;
+        return LA_RUNNING;
+    }
+    if (e->Type == LA_MOUSEMOVE){
+        if (uid->TargetIndexVali == 1){
+            if (!p->SL && !p->SR) p->TX = p->X + e->x - uid->LastX;
+            if (!p->ST && !p->SB) p->TY = p->Y + e->y - uid->LastY;
+            laNotifyUsersPPPath(&p->PP, "position");
+            la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH);
+            laRecalcCurrentPanel();
+            return LA_RUNNING;
+        }elif (uid->TargetIndexVali == 2){
+            p->TW += e->x - uid->LastX; p->TH += e->y - uid->LastY;
+            uid->LastX = e->x; uid->LastY = e->y;
+            p->BoundUi=0;
+            laNotifyUsersPPPath(&p->PP, "size");
+            la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH);
+            laRecalcCurrentPanel();
+            return LA_RUNNING;
+        }elif (uid->TargetIndexVali == 3){
+            laUiList *suil = uid->Ptr1; laUiItem *pui = uid->Ptr2;
+            int IsVertical=uid->On;
+            uid->TargetIndexValf+=IsVertical?la_ScrollerVerticalPan(e->y - uid->LastY, p, uid->Ptr1, uid->Ptr2):
+                                        (pui?la_ScrollerHorizontalPan(e->x - uid->LastX, p, uid->Ptr1, uid->Ptr2):0);
+            uid->Dragging = (int)uid->TargetIndexValf; uid->TargetIndexValf-=uid->Dragging;
+            int pV=uid->Dragging*IsVertical, pH=uid->Dragging*(!IsVertical);
+            if (!pui) laPanUiList(suil, pH, pV,0, p->W, suil->U, p->H-(*p->BT)->BM);
+            else laPanUiList(suil, pH, pV, suil->L, pui->R-(suil->ScrollerShownV?(LA_SCROLL_W+(*p->BT)->RM):0),
+                                           suil->U, pui->B-(*p->BT)->BM-(suil->ScrollerShownH?(LA_SCROLL_W+(*p->BT)->BM):0));
+            uid->LastX = e->x; uid->LastY = e->y;
+            laRedrawCurrentPanel();
+            return LA_RUNNING;
+        }
+    }
+    if (e->Type == LA_L_MOUSE_UP){
+        uid->TargetIndexVali = 0;
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING;
+}
+
+int OPCHK_IsPanel(laPropPack *This, laStringSplitor *ss){
+    if (This && This->LastPs->p == _LA_PROP_PANEL) return 1;
+    else{
+        char *PanelInternalID = strGetArgumentString(ss, "panel_id");
+        if (!PanelInternalID) return 0;
+        else
+            return 1;
+    }
+    return 0;
+}
+int OPCHK_IsPanelNoInstructions(laPropPack *This, laStringSplitor *ss){
+    if (This && This->LastPs->p == _LA_PROP_PANEL) return 1;
+    return 0;
+}
+int OPINV_HidePanel(laOperator *a, laEvent *e){
+    laPanel *p = a->This->LastPs->UseInstance;
+
+    laHidePanelWithDissoveEffect(p);
+
+    return LA_FINISHED;
+}
+int OPINV_ActivatePanel(laOperator *a, laEvent *e){
+    laStringSplitor *ss = a->ExtraInstructionsP;
+    char *TemplateID = strGetArgumentString(ss, "panel_id");
+    if (!TemplateID) return LA_CANCELED;
+
+    laActivatePanel(TemplateID, e->x, e->y);
+
+    return LA_FINISHED;
+}
+int OPINV_PanPanel(laOperator *a, laEvent *e){
+    laPanel *p = a->This->LastPs->UseInstance;
+
+    //laHidePanel(p);
+
+    return LA_FINISHED;
+}
+
+int OPCHK_IsHyper(laPropPack *This, laStringSplitor *ss){
+    if (This && This->LastPs->p->Container->Hyper) return 1;
+    return 0;
+}
+int OPINV_ViewHyperData(laOperator *a, laEvent *e){
+    char buf[2048]={0};
+    memHyperInfo(a->This, buf);
+    printf("%s",buf);
+    return LA_FINISHED;
+}
+
+int OPINV_TranslationDumpMisMatch(laOperator *a, laEvent *e){
+
+    transDumpMissMatchRecord("TranslationDump.txt");
+    laEnableMessagePanel(a, 0, "OK", "Untranslated strings exported to TranslationDump.txt", e->x - 250, e->y - 10, 300, e);
+
+    return LA_FINISHED;
+}
+
+int OPINV_OpenInternetLink(laOperator *a, laEvent *e){
+    char *link = strGetArgumentString(a->ExtraInstructionsP, "link");
+
+    if (link) laOpenInternetLink(link);
+
+    return LA_FINISHED;
+}
+
+void la_RegisterBuiltinOperators(){
+    laPropContainer *pc; laProp *p;
+    laOperatorType *at;
+    laEnumProp *ep;
+
+    laCreateOperatorType("LA_terminate_program", "Quit", "Terminate Program Immediately",
+                          OPCHK_TerminateProgram, 0, 0, OPINV_TerminateProgram, 0, L'⏻', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_undo", "Undo", "Undo from recorded data state", 0, 0, 0, OPINV_Undo, 0, L'⮌', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_redo", "Redo", "Redo using recorded data state", 0, 0, 0, OPINV_Redo, 0, L'⮎', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_translation_dump", "Dump Untranslated Text", "Dump Untranslated Text To File", 0, 0, 0, OPINV_TranslationDumpMisMatch, 0, L'📥', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_open_internet_link", "Goto", "Open Internet Link", 0, 0, 0, OPINV_OpenInternetLink, 0, L'🌐', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_system_paste", "Window Paste", "Generate a syetem paste event",  0, 0, 0, OPINV_SystemPaste, 0, L'📋', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_string_copy", "Copy", "Copy string to clip board", 0, 0, 0, OPINV_StringCopy, 0, L'🗍', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+
+    laCreateOperatorType("LA_window_operator", "Window Operator", "Handle All Unhandled Events",  0, 0, 0, OPINV_Window, OPMOD_Window, L'🖦', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+
+    at = laCreateOperatorType("LA_switch_layout", "Switch Layout", "Cycle All Layouts In Current Window", 0, 0, 0, OPINV_SwitchLayout, OPMOD_FinishOnData, L'↔', LA_ACTUATOR_SYSTEM);
+    at->UiDefine=laui_LayoutCycle;
+
+    at = laCreateOperatorType("LA_new_window", "New Window", "Create a new window", 0, 0, 0, OPINV_NewWindow, 0, L'🗗', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_combine_child_blocks", "Combine Child Block", "If Child Blocks Are Two Panel Blocks, Then Combine Them.",
+                          OPCHK_CombineChildBlocks, 0, 0, OPINV_CombineChildBlocks, 0, L'□' , LA_ACTUATOR_SYSTEM);
+    at = laCreateOperatorType("LA_new_panel", "New Panel", "Create a new panel",
+                          0, 0, 0, OPINV_NewPanel, OPMOD_NewPanel, L'🞆', LA_ACTUATOR_SYSTEM);
+    pc = laDefineOperatorProps(at, 0);
+    p = laAddSubGroup(pc, "template", "Template", "Template selection used to create the new panel", "panel_template", 0, 0, laui_TitleOnly, -1, laget_FirstPanelTemplate, laget_NewPanelGetActiveTemplate, laget_ListNext, 0, 0, laset_NewPanelSetTemplate,0,0);
+    at->UiDefine=laui_PanelTemplateSelect;
+
+    laCreateOperatorType("LA_block_fold_title", "Fold Title", "Fold the tile bar of the block", 0, 0, 0, OPINV_BlockFoldTitle, 0, L'⯅', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_block_maximize", "Maximize", "Maximize this block", 0, 0, 0, OPINV_BlockMaximize, 0, L'⮼', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_block_tear_off_panel", "Tear Off", "Tear off current panel in the block",
+                          OPCHK_BlockHasMorePanels, 0, 0, OPINV_BlockTearOffPanel, 0, L'🗗', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_block_close_panel", "Close Panel", "Close current panel in the block",
+                          OPCHK_BlockHasMorePanels, 0, 0, OPINV_BlockClosePanel, OPMOD_BlockClosePanel, L'❌', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_canvas_ui_maximize", "Maximize", "Maximize this UI item", 0, 0, 0, OPINV_CanvasUiMaximize, 0, L'⮼', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_hide_menu_bar", "Hide Menu Bar", "Hide menu bar of the window", 0, 0, 0, OPINV_HideMenuBar, 0, L'⯅', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_new_layout", "New Layout", "Create a new layout in the window",
+                          0, 0, 0, OPINV_NewLayout, 0, L'🞦', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_panel_operator", "Panel Operator", "Handle Events On The Panel Level",
+                          0, 0, OPEXT_Panel, OPINV_Panel, OPMOD_Panel, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_modal_panel_operator", "Modal Panel Operator", "Handle Events On Modal Panels Like Yes-No Boxes",
+                          0, 0, OPEXT_Panel, OPINV_Panel, OPMOD_ModalPanel, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_menu_panel_operator", "Menu Panel Operator", "Handle Events On Menu Panel,Recieve And Dispatch Confirm Messages,Then Self-destroy.",
+                          0, 0, OPEXT_Panel, OPINV_Panel, OPMOD_MenuPanel, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+
+    laCreateOperatorType("LA_panel_activator", "Panel Activator", "Show A Panel When Invoked.Need An Extra Argument[panel_id]",
+                          OPCHK_IsPanel, 0, 0, OPINV_ActivatePanel, 0, 0, LA_ACTUATOR_SYSTEM)
+        ->ParseArgs = la_PanelActiviatorParser;
+    laCreateOperatorType("LA_hide_panel", "Hide Panel", "Hide a panel",
+                          OPCHK_IsPanel, 0, 0, OPINV_HidePanel, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_dock_panel", "Dock Panel", "Dock a panel",
+                          OPCHK_IsPanel, 0, 0, OPINV_DockPanel, 0, 0, LA_ACTUATOR_SYSTEM);
+    
+    laCreateOperatorType("LA_int_restore_default", "Restore Default Value", "Restore Int Value To Default", OPCHK_IntSetValue, 0, 0, OPINV_IntSetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_real_restore_default", "Restore Default Value", "Restore Float Value To Default", OPCHK_FloatSetValue, 0, 0, OPINV_FloatSetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_int_set_max", "Set Max Value", "Set Int Value To Max", OPCHK_IntSetValue, 0, 0, OPINV_IntSetMax, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_real_set_max", "Set Max Value", "Set Float Value To Max", OPCHK_FloatSetValue, 0, 0, OPINV_FloatSetMax, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_int_set_min", "Set Min Value", "Set Int Value To Min", OPCHK_IntSetValue, 0, 0, OPINV_IntSetMin, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_real_set_min", "Set Min Value", "Set Float Value To Min", OPCHK_FloatSetValue, 0, 0, OPINV_FloatSetMin, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_int_array_restore_default", "Restore Default Array/Value", "Restore Int Values To Default", OPCHK_IntArraySetValue, 0, 0, OPINV_IntArraySetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_real_array_restore_default", "Restore Default Array/Value", "Restore Float Values To Default", OPCHK_FloatArraySetValue, 0, 0, OPINV_FloatArraySetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_int_array_set_max", "Set Max Values", "Set Int Values To Max", OPCHK_IntArraySetValue, 0, 0, OPINV_IntArraySetMax, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_real_array_set_max", "Set Max Values", "Set Float Values To Max", OPCHK_FloatArraySetValue, 0, 0, OPINV_FloatArraySetMax, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_int_array_set_min", "Set Min Values", "Set Int Values To Min", OPCHK_IntArraySetValue, 0, 0, OPINV_IntArraySetMin, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_real_array_set_min", "Set Min Values", "Set Float Values To Min", OPCHK_FloatArraySetValue, 0, 0, OPINV_FloatArraySetMin, 0, 0, LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_enum_restore_default", "Restore Default Value", "Restore enum value to default", OPCHK_EnumSetValue, 0, 0, OPINV_EnumSetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_enum_array_restore_default", "Restore Default Array", "Restore enum array values to default", OPCHK_EnumArraySetValue, 0, 0, OPINV_EnumArraySetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_string_set_default", "Set Default Value", "Set default string", OPCHK_StringSetValue, 0, 0, OPINV_StringSetDefault, 0, L'⭯', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_string_get_folder_path", "Get folder Path", "get folder path", OPCHK_StringSetValue, 0, 0, OPINV_StringGetFolderPath, OPMOD_StringGetFolderOrFilePath, L'📁', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_string_get_file_path", "Get folder Path", "get file path", OPCHK_StringSetValue, 0, 0, OPINV_StringGetFilePath, OPMOD_StringGetFolderOrFilePath, L'🖹', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_sub_put_data_block", "Put Data Block", "Put Pending Data Block Here",
+                          OPCHK_SubPutDataBlock, 0, 0, OPINV_SubPutDataBlock, 0, L'🡮', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    at = laCreateOperatorType("LA_sub_restore_data_block", "Put Data Block", "Put Pending Data Block Here",
+                               OPCHK_SubRestoreDataBlock, 0, OPEXT_SubRestoreDataBlock, OPINV_SubRestoreDataBlock, 0, L'🔗', LA_ACTUATOR_SYSTEM);
+    at->UiDefine = laui_DataRestorePage;
+
+    laCreateOperatorType("LA_view_hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", OPCHK_IsHyper, 0, 0, OPINV_ViewHyperData, 0, L'🛈', LA_ACTUATOR_SYSTEM);
+    
+    laCreateOperatorType("LA_file_dialog_up", "Up", "Select Upper Folder Level", OPCHK_IsFileBrowser, 0, 0, OPINV_FileBrowserUpLevel, 0, L'🢰', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    at = laCreateOperatorType("LA_file_dialog", "File Dialog", "Do File Operations", 0, 0, OPEXT_FileBrowser, OPINV_FileBrowser, OPMOD_FileBrowser, L'🗐', LA_ACTUATOR_SYSTEM);
+    pc = laDefineOperatorProps(at, 2);
+    at->UiDefine = laui_FileBrowserFileList;
+    _LA_PROP_FILE_BROWSER = pc;
+
+    laAddStringProperty(pc, "path", "Path", "Directort Path", 0, 0, 0, "/", 0, offsetof(laFileBrowser, Path), 0, 0, laset_FileBrowserPath, 0, LA_UDF_LOCAL);
+    laAddStringProperty(pc, "file_name", "File Name", "File Name", 0, 0, 0, 0, 0, offsetof(laFileBrowser, FileName), 0, 0, 0, 0, LA_UDF_LOCAL);
+    laAddSubGroup(pc, "file_list", "File List", "List Of Files And Directories Under A Specific Path", "file_item",0,0,laui_FileBrowserFileItem, -1, 0, laget_FileBrowserActiveFile, 0, 0, 0, laset_FileBrowserSelectFile, offsetof(laFileBrowser, FileList), 0);
+    laAddSubGroup(pc, "disk_list", "Disk List", "List Of All Logical Drives (In Windows)", "disk_item",0, 0, 0, -offsetof(laFileBrowser, RootDisk), 0, 0, 0, 0, 0, laset_FileBrowserActiveDisk, offsetof(laFileBrowser, Disks), 0);
+    ep = laAddEnumProperty(pc, "select_what", "Select What", "Select folder or file", 0, 0, 0, 0, 0, offsetof(laFileBrowser, SelectFolder), 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);{
+        laAddEnumItemAs(ep, "file", "File", "File", LA_FILE_SELECT_FILE, L'📁');
+        laAddEnumItemAs(ep, "folder", "Folder", "Folder", LA_FILE_SELECT_FOLDER, L'🖹');
+    }
+    laAddOperatorProperty(pc, "folder_up", "Up", "Select Upper Folder Level In File Browsers", "LA_file_dialog_up", L'🢰', 0);
+    p = laAddPropertyContainer("disk_item", "Disk Item", "A Logical Drive (In Windows)", 0, laui_FileBrowserDiskItem, 0, 0, 0, 0);{
+        laAddStringProperty(p, "id", "ID", "Disk Identifier", 0, 0, 0, 0, 0, 0, 0, laget_FileBrowserDiskID, 0, 0, 0);
+        laAddFloatProperty(p, "total_gb", "Total", "Disk Total Compacity In Gigabytes", 0, 0, "GB", 0, 0, 0, 0, 0, offsetof(laDiskItem, Total_GB), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+        laAddFloatProperty(p, "free_gb", "Free", "Disk Free Space Size In Gigabytes", 0, 0, "GB", 0, 0, 0, 0, 0, offsetof(laDiskItem, Free_GB), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+    }
+    p = laAddPropertyContainer("file_item", "File Item", "A File Item In A List", L'🖹', 0, 0, 0, 0, 0);{
+        laAddStringProperty(p, "name", "Name", "The Name Of The File (With Extension)", 0, 0, 0, 0, 0, offsetof(laFileItem, Name), 0, 0, 0, 0, LA_UDF_LOCAL);
+        laAddIntProperty(p, "is_folder", "Is Folder", "File Is A Folder Or Actual File", 0, 0, 0, 1, 0, 0, 0, 0, offsetof(laFileItem, IsFolder), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+        laAddSubGroup(p, "time_modified", "Time Last Modified", "The Time When The File Was Last Modified", "time_info",0, 0, 0, offsetof(laFileItem, TimeModified), 0, 0, 0, 0, 0, 0, 0, LA_UDF_LOCAL);
+        laAddIntProperty(p, "size", "Size", "File Size In Bytes", 0, 0, "Bytes", 0, 0, 0, 0, 0, offsetof(laFileItem, Size), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+        ep = laAddEnumProperty(p, "type", "Type", "General Type Of The File", 0, 0, 0, 0, 0, offsetof(laFileItem, Type), 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);{
+            laAddEnumItemAs(ep, "unknown", "Unknown", "Unknown/Uncategorized File Type", LA_FILETYPE_UNKNOWN, L'🖹');
+            laAddEnumItemAs(ep, "udf", "UDF", "Uniform Data Format", LA_FILETYPE_UDF, L'📦');
+            laAddEnumItemAs(ep, "document", "Document", "Document File", LA_FILETYPE_DOCUMENT, L'🖹');
+            laAddEnumItemAs(ep, "image", "Image", "Image File", LA_FILETYPE_IMAGE, L'🖻');
+            laAddEnumItemAs(ep, "audio", "Audio", "Audio File", LA_FILETYPE_AUDIO, L'𝄞');
+            laAddEnumItemAs(ep, "video", "Video", "Video File", LA_FILETYPE_VIDEO, L'🎞');
+            laAddEnumItemAs(ep, "compressed", "Compressed", "Compressed File", LA_FILETYPE_COMPRESSED, L'🗜');
+            laAddEnumItemAs(ep, "font", "Font", "Font File", LA_FILETYPE_FONT, L'🗚');
+            laAddEnumItemAs(ep, "vector", "Vector", "Vector File", LA_FILETYPE_VECTOR, L'🞎');
+            laAddEnumItemAs(ep, "webpage", "Webpage", "Webpage", LA_FILETYPE_WEBPAGE, L'🌐');
+            laAddEnumItemAs(ep, "meta", "Meta Data", "Meta Data Package", LA_FILETYPE_META, L'🖹');
+            laAddEnumItemAs(ep, "blend", "Blend", "Blend File", LA_FILETYPE_BLEND, L'🖹');
+            laAddEnumItemAs(ep, "pdf", "PDF", "PDF File", LA_FILETYPE_PDF, L'🖹');
+            laAddEnumItemAs(ep, "exe", "Executable", "Window Executable", LA_FILETYPE_EXEC, L'🖦');
+            laAddEnumItemAs(ep, "sys", "System", "System Files", LA_FILETYPE_SYS, L'🖹');
+            laAddEnumItemAs(ep, "folder", "Folder", "Folder", LA_FILETYPE_FOLDER, L'📁');
+            laAddEnumItemAs(ep, "lasdexchange", "LaSDExchange", "LA Scene Descriptive Exchange File", LA_FILETYPE_LASDEXCHANGE, 0);
+        }
+    }
+
+    at = laCreateOperatorType("LA_udf_append", "Append", "Append A UDF Data Block", 0, 0, OPEXT_UDFOperation, OPINV_UDFAppend, OPMOD_UDFAppend, L'📑', LA_ACTUATOR_SYSTEM);
+    pc = laDefineOperatorProps(at, 0);
+    at->UiDefine = laui_LinkerPanel;
+    laAddSubGroup(pc, "root_nodes", "UDF Nodes", "List Of All Linkable/Appendable Nodes In The File", "udf_content_node",0, 0, laui_LinkerSelectionProp, -1, 0, 0, 0, 0, 0, 0, offsetof(laUDFPreviewExtra, ContentNodes), 0);
+
+    at = laCreateOperatorType("LA_udf_save_instance", "Save Instance", "Save a instance as a UDF block", 0, 0, OPEXT_UDFOperation, OPINV_UDFSaveInstance, OPMOD_UDFSaveInstance, L'📑', LA_ACTUATOR_SYSTEM);
+
+    at = laCreateOperatorType("LA_managed_save", "Managed Save", "Save managed data blocks", 0, 0, OPEXT_ManagedSave, OPINV_ManagedSave, OPMOD_ManagedSave, L'🖫', LA_ACTUATOR_SYSTEM);
+    pc = laDefineOperatorProps(at, 1);
+    ep=laAddEnumProperty(pc, "show_page", "Show Page", "Show whether data blocks or UDF files", 0,0,0,0,0,offsetof(laManagedSaveExtra, ShowPage),0,laset_ManagedSavePage,0,0,0,0,0,0,0,0);
+    laAddEnumItemAs(ep, "DATA_BLOCKS", "Data Blocks", "All data blocks", 0, 0);
+    laAddEnumItemAs(ep, "FILES", "Files", "All Files", 1, 0);
+    at->UiDefine = laui_ManagedSavePanel;
+    
+    laCreateOperatorType("LA_udf_propagate", "Propagate", "Propagate this file to all unassigned child nodes", 0, 0, 0, OPINV_UDFPropagate, 0, 0, LA_ACTUATOR_SYSTEM);
+    
+    laCreateOperatorType("LA_managed_save_new_file", "New File", "New managed UDF file", 0, 0, OPEXT_ManagedSave, OPINV_ManagedSaveNewFile, OPMOD_ManagedSaveNewFile, L'+', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_manage_udf", "UDF Manager", "Operations on all managed UDF files", 0, 0, 0, OPINV_UDFManager, 0, L'🔍', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_add_resource_folder", "Add Resource Folder", "Add a resource folder entry for searching UDF references",
+                               0, 0, 0, OPINV_AddResourceFolder, 0, L'🞧', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_remove_resource_folder", "Remove Resource Folder", "Remove a resource folder entry",
+                               0, 0, 0, OPINV_RemoveResourceFolder, 0, L'❌', LA_ACTUATOR_SYSTEM);
+
+    laCreateOperatorType("LA_confirm", "Confirm", "Confirm The Statement", 0, 0, 0, OPINV_DoNothing, 0, L'✔', LA_ACTUATOR_SYSTEM)
+        ->ExtraInstructions = "feedback=CONFIRM;";
+    laCreateOperatorType("LA_cancel", "Cancel", "Ignore The Statement", 0, 0, 0, OPINV_DoNothing, 0, L'❌', LA_ACTUATOR_SYSTEM)
+        ->ExtraInstructions = "feedback=CANCEL;";
+    laCreateOperatorType("LA_pure_yes_no", "Yes Or No", "Show Yes Or No Box", 0, 0, 0, OPINV_PureYesNo, 0, L'❓', LA_ACTUATOR_SYSTEM);
+    
+    laCreateOperatorType("LA_delete_theme", "Delete Theme", "Delete a theme",
+                               0, 0, 0, OPINV_DeleteTheme, 0, L'❌', LA_ACTUATOR_SYSTEM);
+}

+ 1373 - 0
source/lagui/resources/la_properties.c

@@ -0,0 +1,1373 @@
+#include "../la_5.h"
+
+extern LA MAIN;
+extern struct _tnsMain *T;
+
+void *laget_ActiveTheme(void *unused){
+    return MAIN.CurrentTheme;
+}
+void laset_ActiveTheme(void* unused, laTheme* t){
+    if(!t) MAIN.CurrentTheme = MAIN.Themes.pFirst;
+    else MAIN.CurrentTheme = t;
+    la_RefreshThemeColor(MAIN.CurrentTheme);
+    la_RegenerateWireColors();
+    laRedrawAllWindows();
+}
+void laset_ThemeName(laTheme *t, char *content){
+    strSafeSet(&t->Name, content);
+}
+void laset_ThemeAuthor(laTheme *t, char *content){
+    strSafeSet(&t->Author, content);
+}
+void laset_ThemeColor(laTheme* t, real* array){
+    tnsVectorCopy4d(array,t->Color);
+    la_RefreshThemeColor(t);
+    laRedrawAllWindows();
+}
+void laset_ThemeAccentColor(laTheme* t, real* array){
+    tnsVectorCopy4d(array,t->AccentColor);
+    la_RefreshThemeColor(t);
+    laRedrawAllWindows();
+}
+void laset_ThemeInactiveSaturation(laTheme* t, real a){
+    t->InactiveSaturation=a;
+    la_RefreshThemeColor(t);
+    laRedrawAllWindows();
+}
+void laset_ThemeInactiveMix(laTheme* t, real a){
+    t->InactiveMix=a;
+    la_RefreshThemeColor(t);
+    laRedrawAllWindows();
+}
+void laset_ThemeCursorAlpha(laTheme* t, real a){
+    t->CursorAlpha=a;
+    la_RefreshThemeColorSelf(t);
+    laRedrawAllWindows();
+}
+void laset_ThemeSelectionAlpha(laTheme* t, real a){
+    t->SelectionAlpha=a;
+    la_RefreshThemeColorSelf(t);
+    laRedrawAllWindows();
+}
+void laset_ThemeNormal(laBoxedTheme* bt, real val){
+    bt->NormalY=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeActive(laBoxedTheme* bt, real val){
+    bt->ActiveY=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeBorder(laBoxedTheme* bt, real val){
+    bt->BorderY=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeText(laBoxedTheme* bt, real val){
+    bt->TextY=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeTextActive(laBoxedTheme* bt, real val){
+    bt->TextActiveY=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeAlpha(laBoxedTheme* bt, real val){
+    bt->Alpha=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeMargins(laBoxedTheme* bt, int index, real val){
+    bt->Margins[index]=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemePaddings(laBoxedTheme* bt, int index, real val){
+    bt->Paddings[index]=val;
+    la_RefreshBoxedThemeColor(bt);
+    laRedrawAllWindows();
+}
+void laset_ThemeWireTransparency(laTheme* t, real val){ t->WireTransparency = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeWireBrightness(laTheme* t, real val){ t->WireBrightness = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeWireSaturation(laTheme* t, real val){ t->WireSaturation = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeEdgeTransparency(laTheme* t, real val){ t->EdgeTransparency = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeEdgeBrightness(laTheme* t, real val){ t->EdgeBrightness = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeVertexTransparency(laTheme* t, real val){ t->VertexTransparency = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeVertexBrightness(laTheme* t, real val){ t->VertexBrightness = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeSVertexTransparency(laTheme* t, real val){ t->SelectedVertexTransparency = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeSEdgeTransparency(laTheme* t, real val){ t->SelectedEdgeTransparency = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_ThemeSFaceTransparency(laTheme* t, real val){ t->SelectedFaceTransparency = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+
+void laset_WireColorSlices(void* unused, int val){ MAIN.WireColorSlices = val; la_RegenerateWireColors(); laRedrawAllWindows(); }
+void laset_WireThickness(void* unused, real val){ MAIN.WireThickness = val;laRedrawAllWindows(); }
+void laset_WireSaggyness(void* unused, real val){ MAIN.WireSaggyness = val; laRedrawAllWindows(); }
+
+void* laget_DetachedControllerFirst(void* unused,void* unused2){
+    return MAIN.Controllers.pFirst;
+}
+
+void laset_UiRowHeight(void* unused, int val){
+    MAIN.UiRowHeight = val;
+    la_RefreshThemeColor(MAIN.CurrentTheme);
+    tnsInvalidateFontCache();
+    laRedrawAllWindows();
+}
+void laset_FontSize(void* unused, real val){
+    MAIN.FontSize = val;
+    tnsInvalidateFontCache();
+    laRedrawAllWindows();
+}
+void laset_MarginSize(void* unused, real val){
+    MAIN.MarginSize = val;
+    la_RefreshThemeColor(MAIN.CurrentTheme);
+    laRedrawAllWindows();
+}
+
+void laset_ResourcePath(laResourceFolder *rf, char *content){
+    strSafeSet(&rf->Path, content);
+    laRefreshUDFRegistries();
+}
+
+void *laget_Self(void *p, void *UNUSED){
+    return p;
+}
+
+void *laget_ListNext(laListItem *Item, void *UNUSED){
+    return Item->pNext;
+}
+void *laget_ListPrev(laListItem *Item, void *UNUSED){
+    return Item->pPrev;
+}
+void *laget_List2Next(laListItem2 *Item, void *UNUSED){
+    return Item->pNext;
+}
+void *laget_List2Prev(laListItem2 *Item, void *UNUSED){
+    return Item->pPrev;
+}
+void *laget_PointerListNext(void *UNUSED, laPropIterator *pi){
+    pi->Linker = ((laListItemPointer *)pi->Linker)->pNext;
+    return pi->Linker->p;
+}
+
+void *laget_FirstUiItem(laUiList *uil, void *UNUSED){
+    return uil->UiItems.pFirst;
+}
+void *laget_FirstColumnItem(laUiList *uil, void *UNUSED){
+    if (!uil) return 0;
+    return uil->Columns.pFirst;
+}
+int la_ResetUiColum(laColumn *c, int U, int L, int R, int LR, int repos);
+void laset_ColumnSP(laColumn *c, real val){
+    if (c->LS) c->LS->SP = val;
+    if (c->RS) c->RS->SP = val;
+}
+real laget_ColumnSP(laColumn *c){
+    if (c->LS) return c->LS->SP;
+    else
+        return 0.5;
+}
+void laset_ColumnSnap(laColumn *c, int val){
+    if (c->LS && c->LS->MaxW) c->LS->MaxW = val;
+    if (c->RS && c->RS->MaxW) c->RS->MaxW = val;
+}
+int laget_ColumnSnap(laColumn *c){
+    if (c->LS && c->LS->MaxW) return c->LS->MaxW;
+    if (c->RS && c->RS->MaxW) return c->RS->MaxW;
+    return 20;
+}
+void laset_SnapState(laColumn *c, int val){
+    if (val == 1){
+        if (c->LS) c->LS->MaxW = 20;
+        if (c->RS) c->RS->MaxW = 0;
+    }elif (val == 2){
+        if (c->LS) c->LS->MaxW = 0;
+        if (c->RS) c->RS->MaxW = 20;
+    }else{
+        if (c->LS) c->LS->MaxW = 0;
+        if (c->RS) c->RS->MaxW = 0;
+    }
+}
+int laget_SnapState(laColumn *c){
+    if (c->LS && c->LS->MaxW) return 1;
+    if (c->RS && c->RS->MaxW) return 2;
+    return 0;
+}
+void *laget_BoxedTheme(laTheme *theme){
+    return theme->BoxedThemes.pFirst;
+}
+void *laget_BoxedThemeUi(void *UNUSED){
+    return ((laTheme *)MAIN.Themes.pFirst)->BoxedThemes.pFirst;
+}
+
+void* laget_Main(void *UNUSED, void* UNUSED2){
+    return &MAIN;
+}
+
+laPropContainer* laget_PropertyNodeType(laProp* p){
+    static laPropContainer* pc=0;
+    static laPropContainer* ipc=0;
+    static laPropContainer* fpc=0;
+    switch(p->PropertyType&(~LA_PROP_ARRAY)){
+        case LA_PROP_INT: { if(!ipc) ipc=la_ContainerLookup("int_property"); return ipc; }
+        case LA_PROP_FLOAT: { if(!fpc) fpc=la_ContainerLookup("float_property"); return fpc; }
+        default: { if(!pc) pc=la_ContainerLookup("property_item"); return pc; }
+    }
+}
+
+void *laget_PropertyItemFirst(laPropContainer *p){
+    if (!p) return 0;
+    return p->Props.pFirst;
+}
+void *laget_PropertyItemNext(laProp *p, void *UNUSED){
+    return p->Item.pNext;
+}
+void laget_PropertyName(laProp *p, char *result){
+    strCopyFull(result, p ? p->Name : "");
+}
+void laget_PropertyIdentifier(laProp *p, char *result){
+    strCopyFull(result, p ? p->Identifier : "");
+}
+void laget_PropertyDescription(laProp *p, char *result){
+    strCopyFull(result, p ? p->Description : "");
+}
+int laget_PropertySubContainerIconID(laProp *p){
+    if (p->PropertyType != LA_PROP_SUB) return 0;
+    if (!p->SubProp){
+        p->SubProp = la_ContainerLookup(((laSubProp *)p)->TargetID);
+        if (!p->SubProp) return 0;
+    }
+    return p->SubProp->IconID;
+}
+
+int laget_TrashItemInstance(void *a){
+    return a;
+}
+
+void *laget_ActiveWindow(void *unused){
+    return MAIN.CurrentWindow;
+}
+void *laget_FirstWindow(void *unused, void* unused_iter){
+    return MAIN.Windows.pFirst;
+}
+void *laget_FirstContainer(void *unused, void* unused_iter){
+    return MAIN.PropContainers.pFirst;
+}
+void *laget_WindowFirstLayout(laWindow *window, void* unused_iter){
+    return window->Layouts.pFirst;
+}
+void *laget_FirstHiddenPanel(laWindow *window, void* unused_iter){
+    for(laPanel* p=window->Panels.pFirst;p;p=p->Item.pNext){
+        if(!p->Show&&!p->LaterDestroy){return p;}
+    }
+    return 0;
+}
+void *laget_NextHiddenPanel(laPanel* p, void* unused_iter){
+    for(p=p->Item.pNext;p;p=p->Item.pNext){
+        if(!p->Show&&!p->LaterDestroy){return p;}
+    }
+    return 0;
+}
+void laset_WindowHiddenPanel(laWindow *window, laPanel* p){
+    laShowPanelWithExpandEffect(p);
+    laPopPanel(p);
+    return 0;
+}
+void laget_PanelTitle(laPanel *p, char *result){
+    strCopyFull(result, p->Title->Ptr);
+}
+void laset_PanelTitle(laPanel *p, char *content){
+    strSafeSet(&p->Title, content);
+    p->TitleWidth = tnsStringGetWidth(p->Title->Ptr, 0, 0);
+}
+void laset_PanelSnapDistance(laPanel *p, int index, int n){
+    int a;
+    if (!n) return;
+    switch (index){ //lrtb
+    case 0:
+        p->SL = p->SL ? n : 0;
+        break;
+    case 1:
+        p->SR = p->SR ? n : 0;
+        break;
+    case 2:
+        p->ST = p->ST ? n : 0;
+        break;
+    case 3:
+        p->SB = p->SB ? n : 0;
+        break;
+    }
+}
+void laset_PanelSnapEnable(laPanel *p, int index, int n){
+    laWindow *w = MAIN.CurrentWindow;
+    int a;
+    switch (index){ //lrtb
+    case 0:
+        p->SL = (n && p->X) ? p->X : 0;
+        break;
+    case 1:
+        p->SR = (n && w ? ((a = MAIN.CurrentWindow->CW - p->X - p->W) ? a : 0) : n);
+        break;
+    case 2:
+        p->ST = (n && p->Y) ? p->Y : 0;
+        break;
+    case 3:
+        p->SB = (n && w ? ((a = MAIN.CurrentWindow->CH - p->Y - p->H) ? a : 0) : n);
+        break;
+    }
+}
+void laget_PanelSnapEnable(laPanel *p, int *result){
+    result[0] = p->SL ? 1 : 0;
+    result[1] = p->SR ? 1 : 0;
+    result[2] = p->ST ? 1 : 0;
+    result[3] = p->SB ? 1 : 0;
+}
+void laget_LayoutTitle(laLayout *l, char *result){
+    strCopyFull(result, l->ID->Ptr);
+}
+void laset_LayoutTitle(laLayout *l, char *content){
+    strSafeSet(&l->ID, content);
+    laRenameWindow(MAIN.CurrentWindow, content);
+}
+//void* laget_LayoutPanelFirst(laLayout* l) {
+//	return l->Panels.pFirst;
+//}
+void laget_WindowTitle(laWindow *w, char *result){
+    strCopyFull(result, w->Title->Ptr);
+}
+void laset_WindowTitle(laWindow *w, char *content){
+    strSafeSet(&w->Title, content);
+}
+void laset_WindowActiveLayout(laWindow *w, laLayout *l, int UNUSED_State){
+    la_StopAllOperators();
+    w->CurrentLayout = l;
+    laRenameWindow(w, l->ID->Ptr);
+    laRedrawCurrentWindow();
+}
+//void laget_PanelSnappingTrueFalse(laPanel* p, int* result) {
+//	result[0] = p->SL > 0 ? 1 : 0;
+//	result[1] = p->SR > 0 ? 1 : 0;
+//	result[2] = p->ST > 0 ? 1 : 0;
+//	result[3] = p->SB > 0 ? 1 : 0;
+//}
+//void laset_PanelSnappingTrueFalse(laPanel* p,int Index, int n) {
+//	int* v = &p->SL;
+//	int val = abs(v[Index]);
+//	v[Index] = val*(n ? 1 : -1);
+//}
+
+void laset_PanelMultisample(void* unused, int value){
+    MAIN.PanelMultisample = value;
+    tnsReconfigureTextureParameters(value);
+    laRedrawAllWindows();
+}
+
+void *laget_UiInternalType(void *UNUSED){
+    return MAIN.UiTypes.pFirst;
+}
+
+void laget_TimeString(laTimeInfo *ti, char *result,char** result_direct){
+    sprintf(result, "%d-%.02d-%.02d %.02d:%.02d:%.02d", ti->Year, ti->Month, ti->Day, ti->Hour, ti->Minute, ti->Second);
+}
+int laget_TimeYear(laTimeInfo *ti){
+    return (int)ti->Year;
+}
+int laget_TimeMonth(laTimeInfo *ti){
+    return (int)ti->Month;
+}
+int laget_TimeDay(laTimeInfo *ti){
+    return (int)ti->Day;
+}
+int laget_TimeHour(laTimeInfo *ti){
+    return (int)ti->Hour;
+}
+int laget_TimeMinute(laTimeInfo *ti){
+    return (int)ti->Minute;
+}
+int laget_TimeSecond(laTimeInfo *ti){
+    return (int)ti->Second;
+}
+
+void *laget_ConditionerExtra(laUiItem *ui){
+    if (ui->Type == &_LA_UI_CONDITION ||
+        ui->Type == &_LA_UI_CONDITION_END ||
+        ui->Type == &_LA_UI_CONDITION_ELSE ||
+        ui->Type == _LA_UI_CONDITION_TOGGLE){
+        return ui->Extra;
+    }
+    return 0;
+}
+void *laget_CanvasExtra(laUiItem *ui){
+    if (ui->Type == _LA_UI_CANVAS){
+        return ui->Extra;
+    }
+    return 0;
+}
+
+void laget_MainIdentifier(laUDF *udf, char *result, char** here){
+    strcpy(result, "MAIN");
+}
+void laget_TNSIdentifier(laUDF *udf, char *result, char** here){
+    strcpy(result, "TNS");
+}
+void laget_UDFFilePath(laUDF *udf, char *result, char** here){
+    *here=udf->FileName->Ptr;
+}
+void laget_UDFContentNodeFullPath(laUDFContentNode *ucn, char *result, char** here){
+    if (ucn->FullPath && ucn->FullPath->Ptr) *here=ucn->FullPath->Ptr;
+}
+void laget_UDFContentNodeIdentifier(laUDFContentNode *ucn, char *result, char** here){
+    if (ucn->Identifier && ucn->Identifier->Ptr) *here=ucn->Identifier->Ptr;
+}
+void laget_UDFContentInstanceIdentifier(laUDFContentInstance *uci, char *result, char** here){
+    if (uci->Identifier && uci->Identifier->Ptr) *here=uci->Identifier->Ptr;
+}
+
+void lapost_PropPack(laPropPack *pp);
+void laget_ConditionNodePropPath(laUiConditionNode *ucn, char *result, char** here){
+    if (!ucn->PP.Go) return;
+    la_GetPropPackPath(&ucn->PP, result);
+}
+void laset_ConditionNodePropPath(laUiConditionNode *ucn, char *content, char** here){
+    if (ucn->PP.Go){
+        la_FreePropStepCache(ucn->PP.Go);
+        ucn->PP.LastPs = ucn->PP.Go = 0;
+    }
+    la_GetPropFromPath(&ucn->PP, ucn->PP.RawThis, content, 0);
+}
+void laread_ConditionNodePropPath(laUiConditionNode *ucn, char *Content, char** here){
+    if (!Content || !Content[0]) return;
+    ucn->PP.Go = CreateNewBuffer(char, strlen(Content) + 1);
+    strcpy(ucn->PP.Go, Content);
+}
+void lapost_ConditionNode(laUiConditionNode *ucn){
+    lapost_PropPack(&ucn->PP);
+}
+void laset_ConditionNodeType(laUiConditionNode *ucn, int Type){
+    ucn->Type = Type;
+    switch (Type){
+    case LA_CONDITION_PROP:
+    case LA_CONDITION_INT:
+    case LA_CONDITION_FLOAT:
+    case LA_CONDITION_STRING:
+    case LA_CONDITION_FALSE:
+    case LA_CONDITION_TRUE:
+        la_ConditionNodeFreeRecursive(ucn->Expression1);
+        la_ConditionNodeFreeRecursive(ucn->Expression2);
+        ucn->Expression1 = 0;
+        ucn->Expression2 = 0;
+        if (ucn->PP.LastPs) la_FreePropStepCache(ucn->PP.Go);
+        ucn->PP.LastPs = ucn->PP.Go = ucn->PP.RawThis = 0;
+        break;
+    case LA_CONDITION_NOT:
+        la_ConditionNodeFreeRecursive(ucn->Expression2);
+        ucn->Expression2 = 0;
+        if (ucn->PP.LastPs) la_FreePropStepCache(ucn->PP.Go);
+        ucn->PP.LastPs = ucn->PP.Go = ucn->PP.RawThis = 0;
+        if (!ucn->Expression1) ucn->Expression1 = laIntExpression(0);
+        break;
+    default:
+        if (!ucn->Expression1) ucn->Expression1 = laIntExpression(0);
+        if (!ucn->Expression2) ucn->Expression2 = laIntExpression(1);
+        break;
+    }
+    laRecalcCurrentPanel();
+}
+void laread_ConditionNodeType(laUiConditionNode *ucn, int Type){
+    ucn->Type = Type;
+}
+
+void *tnsget_TnsMain(void *unused){
+    return T;
+}
+void *tnsget_World(void *unused){
+    return &T->World;
+}
+void *tnsread_World(void *unused, void *inst){
+}
+void *tnsget_detached_FirstRootObject(void *UNUSED1, void *UNUSED2){
+    return T->World.RootObjects.pFirst;
+}
+void *tnsget_detached_FirstTexture(void *UNUSED1, void *UNUSED2){
+    return T->Textures.pFirst;
+}
+void *tnsget_PreviewTexture(void *UNUSED){
+    return T->PreviewTexture;
+}
+void *tnsset_PreviewTexture(void *UNUSED_PARENT, void *tex, int UNUSEDSTATE){
+    T->PreviewTexture = tex;
+}
+void tnsget_ObjectName(tnsObject *s, char *result){
+    if (!s->Name) return;
+    strCopyFull(result, s->Name->Ptr);
+}
+void tnsset_ObjectName(tnsObject *s, char *content){
+    strSafeSet(&s->Name, content);
+}
+void *tnsget_NextLinkedObject(tnsObject *o, laPropIterator *pi){
+    pi->Linker = ((laListItemPointer *)pi->Linker->pNext);
+    return pi->Linker->p;
+}
+void *tnsget_FirstChildObject(tnsObject *ob){
+    return ob->ChildObjects.pFirst;
+}
+
+void tnsset_ObjectLocation(tnsObject* o, real val, int n){ o->Location[n]=val; tnsSelfTransformValueChanged(o); laNotifyUsers("tns.world"); }
+void tnsset_ObjectRotation(tnsObject* o, real val, int n){ o->Rotation[n]=val; tnsSelfTransformValueChanged(o); laNotifyUsers("tns.world"); }
+void tnsset_ObjectScale(tnsObject* o, real val){ o->Scale=val; tnsSelfTransformValueChanged(o); laNotifyUsers("tns.world"); }
+
+void laget_UiTemplateIdentifier(laUiTemplate *uit, char *result, char** here){
+    *here=uit->Identifier->Ptr;
+}
+void laset_UiTemplateIdentifier(laUiTemplate *uit, char *content){
+    strSafeSet(&uit->Identifier, content);
+}
+void laget_UiDataPath(laUiItem *ui, char *result){
+    laPropStep *ps = ui->PP.Go;
+    if (ui->PP.LastPs || ui->PP.Go){
+        for (ps; ps; ps = ps->pNext){
+            if (ps->Type == L'@' || ps->Type == L'#' || ps->Type == L'='){
+                strcat(result, ps->p);
+            }else{
+                strcat(result, ps->p->Identifier);
+            }
+            if (ps->pNext){
+                if (ps->pNext->Type == L'.') strcat(result, ".");
+                elif (ps->pNext->Type == L'#') strcat(result, "#");
+                elif (ps->pNext->Type == L'@') strcat(result, "@");
+                elif (ps->pNext->Type == L'=') strcat(result, "= ");
+                elif (ps->pNext->Type == L'$') strcat(result, "$");
+            }
+        }
+    }elif (ui->AT){
+        strcpy(result, "");
+    }
+}
+void laget_UiOperatorID(laUiItem *ui, char *result, char** here){
+    if (ui->AT){
+        *here=ui->AT->Identifier;
+    }else *result=0;
+}
+void laread_UiDataPath(laUiItem *ui, char *Content){
+    if (!Content || !Content[0]) return;
+    ui->PP.Go = CreateNewBuffer(char, strlen(Content) + 1);
+    strcpy(ui->PP.Go, Content);
+}
+void laread_UiOperatorID(laUiItem *ui, char *Content){
+    ui->AT = laGetOperatorType(Content);
+}
+
+void *laget_PanelTemplate(void *UNUSED, void *UNUSED2){
+    return MAIN.PanelTemplates.pFirst;
+}
+
+void lapost_Window(laWindow *w){
+    la_CreateSystemWindow(w);
+    MAIN.CurrentWindow = w;
+    laStartWindow(w);
+}
+void lapost_PropPack(laPropPack *pp){
+    char *path = pp->Go;
+    if (pp->LastPs /* || !path*/) return;
+    if ((!path || (path && !path[0])) && pp->RawThis) pp->LastPs = pp->RawThis->LastPs;
+    if (pp->RawThis) lapost_PropPack(pp->RawThis);
+    pp->Go = 0;
+    la_GetPropFromPath(pp, pp->RawThis, path, 0);
+    FreeMem(path);
+}
+void lapost_UiItem(laUiItem *ui){
+    lapost_PropPack(&ui->PP);
+    //if(ui->Type == _LA_UI_CANVAS) ui->Type->Init(ui);
+}
+void lapostim_UiItem(laUiItem *ui){
+    if (ui->Type && ui->Type->Init && ui->Type != _LA_UI_CANVAS && ui->Type != &_LA_UI_CONDITION) ui->Type->Init(ui);
+    ui->State = ui->State ? ui->State : (ui->Type ? LA_UI_NORMAL : 0);
+
+    la_AssignPropExtras(ui);
+}
+void lapost_Panel(laPanel *p){
+    p->PP.EndInstance = p;
+    p->PP.LastPs = &p->FakePS;
+    p->PP.LastPs->p = _LA_PROP_PANEL;
+
+    la_EnsurePanelExtras(p);
+
+    p->Refresh = LA_TAG_RECALC;
+}
+
+
+//void laget_DetachedPropContainerID(laProp* p, char * result) {
+//	strcpy(result, p->Detached->Container->Identifier);
+//}
+//void laget_DetachedPropPropID(laProp* p, char * result) {
+//	strcpy(result, p->Detached->Identifier);
+//}
+//void laset_DetachedPropContainerID(laProp* p, char * content) {
+//	p->Description = CreateNewBuffer(char, 128);
+//	strcpy(p->Description, content);
+//}
+//void laset_DetachedPropPropID(laProp* p, char * content) {
+//	p->Name = CreateNewBuffer(char, 128);
+//	strcpy(p->Name, content);
+//}
+void laread_DetachedPropRename(laProp *p, char *content){
+    p->Identifier = CreateNewBuffer(char, 128);
+    strcpy(p->Identifier, content);
+}
+void laget_DetachedPropPath(laProp *p, char *result, char** here){
+    la_GetPropPackPath(&p->DetachedPP, result);
+}
+void laread_DetachedPropPath(laProp *p, char *content){
+    p->DetachedPP.Go = CreateNewBuffer(char, 128);
+    strcpy(p->DetachedPP.Go, content);
+}
+void lapost_DetachedProp(laProp *Prop){
+    laPropContainer *pc = 0;
+    laSubProp *np = 0;
+    laIntProp *ip;
+    laFloatProp *fp;
+    laEnumProp *ep;
+    laSubProp *sp;
+    char *path = Prop->DetachedPP.Go;
+    char *id = Prop->Identifier;
+    laPropPack TempPP = {0};
+    laListItem Item;
+
+    Prop->DetachedPP.Go = 0;
+    memcpy(&Item, &Prop->Item, sizeof(laListItem));
+
+    la_GetPropFromPath(&TempPP, Prop->DetachedPP.RawThis, path, 0);
+    //FreeMem(path);
+
+    memcpy(Prop, TempPP.LastPs->p, la_GetPropertySize(TempPP.LastPs->p->PropertyType));
+
+    memcpy(&Prop->DetachedPP, &TempPP, sizeof(laPropPack));
+    memcpy(&Prop->Item, &Item, sizeof(laListItem));
+
+    switch (Prop->PropertyType){
+    case LA_PROP_INT:
+    case LA_PROP_INT | LA_PROP_ARRAY:
+        ip = Prop;
+        ip->Detached = CreateNewBuffer(int, Prop->Len ? Prop->Len : 1);
+        break;
+    case LA_PROP_FLOAT:
+    case LA_PROP_FLOAT | LA_PROP_ARRAY:
+        fp = Prop;
+        fp->Detached = CreateNewBuffer(real, Prop->Len ? Prop->Len : 1);
+        break;
+    case LA_PROP_ENUM:
+    case LA_PROP_ENUM | LA_PROP_ARRAY:
+        ep = Prop;
+        ep->Detached = CreateNewBuffer(int, 1);
+        ep->Detached[0] = ((laEnumItem *)ep->Items.pFirst)->Index;
+    }
+
+    Prop->Identifier = id;
+}
+
+void tnspost_Object(tnsObject *o){
+    /* what */
+}
+void tnspropagate_Object(tnsObject* o, laUDF* udf, int force){
+    for(laListItemPointer* lip=o->ChildObjects.pFirst;lip;lip=lip->pNext){ if(!lip->p) continue;
+        if(force || !laget_InstanceActiveUDF(lip->p)){ laset_InstanceUDF(lip->p, udf); tnspropagate_Object(lip->p,udf,force); }
+    }
+}
+void tnstouched_Object(tnsObject *o, int hint){
+    printf("touched\n");
+    if(o->Type==TNS_OBJECT_MESH && (hint&TNS_HINT_GEOMETRY)){
+        tnsInvaliateMeshBatch(o);
+    }
+    laNotifyUsers("tns.world");
+}
+
+int tnsget_MeshObjectVertSize(tnsMeshObject* o){ return o->totv*sizeof(tnsVert);/*can't use maxv*/ }
+int tnsget_MeshObjectEdgeSize(tnsMeshObject* o){ return o->tote*sizeof(tnsEdge);/*can't use maxv*/ }
+void* tnsget_MeshObjectFaceRaw(tnsMeshObject* o, int* r_size, int* r_is_copy){
+    int* arr=0; int next=0,max=0; int i=0;
+    arrEnsureLength(&arr, i, &max, sizeof(int));
+    arr[i]=o->totf; i++;
+    for(int f=0;f<o->totf;f++){
+        arrEnsureLength(&arr, i+o->f[f].looplen+2, &max, sizeof(int));
+        arr[i]=o->f[f].looplen; i++;
+        arr[i]=o->f[f].flags; i++;
+        for(int l=0;l<o->f[f].looplen;l++){
+            arr[i]=o->f[f].loop[l]; i++;
+        }
+    }
+    *r_size = i*sizeof(int);
+    *r_is_copy = 1;
+    return arr; 
+}
+void tnsset_MeshObjectFaceRaw(tnsMeshObject* o, int* data, int s){
+    int totf=data[0]; int i=1;
+    if(o->f){
+        for(int fi=0;fi<o->totf;fi++){
+            if(o->f[fi].loop) free(o->f[fi].loop);
+        }
+        arrFree(&o->f, &o->maxf); o->totf=0; 
+    }
+    o->f=calloc(1,sizeof(tnsFace)*totf); o->maxf=o->totf=totf;
+    for(int fi=0;fi<totf;fi++){
+        tnsFace*f=&o->f[fi];
+        f->looplen=data[i]; i++;
+        f->flags=data[i]; i++;
+        f->loop=calloc(1,sizeof(int)*f->looplen);
+        for(int li=0;li<f->looplen;li++){
+            f->loop[li]=data[i]; i++;
+        }
+    }
+}
+
+
+laPropContainer* tnsget_ObjectType(tnsObject* o){
+    switch(o->Type){
+    case TNS_OBJECT_EMPTY: default: return TNS_PC_OBJECT_GENERIC;
+    case TNS_OBJECT_CAMERA: return TNS_PC_OBJECT_CAMERA;
+    case TNS_OBJECT_MESH:   return TNS_PC_OBJECT_MESH;
+    case TNS_OBJECT_LIGHT:  return TNS_PC_OBJECT_LIGHT;
+    }
+}
+
+laPropContainer* LA_PC_SOCKET_IN;
+laPropContainer* LA_PC_SOCKET_OUT;
+laPropContainer* TNS_PC_OBJECT_GENERIC;
+laPropContainer* TNS_PC_OBJECT_CAMERA;
+laPropContainer* TNS_PC_OBJECT_LIGHT;
+laPropContainer* TNS_PC_OBJECT_MESH;
+
+void la_RegisterGeneralProps(){
+    laPropContainer *p, *ip, *p2, *ip2, *sp1, *sp2;
+    laProp *ep;
+    laPropPack pp;
+    laSubProp *sp;
+    laKeyMapper *km;
+
+    p = la_SetGeneralRoot(&MAIN.GeneralIntSub, "__general_int__", "Genral Int Operations", "Genral Int Operations");
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_int_restore_default", L'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_int_set_max", 0, 0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_int_set_min", 0, 0);
+    laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", L'🛈', 0);
+
+    p = la_SetGeneralRoot(&MAIN.GeneralIntArraySub, "__general_int_arr__", "Genral Int Array Operations", "Genral Int Array Operations");
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_int_array_restore_default", L'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_int_array_set_max", 0, 0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_int_array_set_min", 0, 0);
+    laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", L'🛈', 0);
+
+    p = la_SetGeneralRoot(&MAIN.GeneralFloatSub, "__general_real__", "Genral Float Operations", "Genral Float Operations");
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_real_restore_default", L'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_real_set_max", 0, 0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_real_set_min", 0, 0);
+    laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", L'🛈', 0);
+
+    p = la_SetGeneralRoot(&MAIN.GeneralFloatArraySub, "__general_real_arr__", "Genral Float Array Operations", "Genral Float Array Operations");
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_real_array_restore_default", L'⭯', 0);
+    laAddOperatorProperty(p, "set_max", "Set Max", "Set The Property To The Max Value", "LA_real_array_set_max", 0, 0);
+    laAddOperatorProperty(p, "set_min", "Set Min", "Set The Property To The Min Value", "LA_real_array_set_min", 0, 0);
+    laAddOperatorProperty(p, "hyper_data", "View Hyper Data", "Show Properties Of Specific Data Block", "LA_view_hyper_data", L'🛈', 0);
+
+    p = la_SetGeneralRoot(&MAIN.GeneralEnumSub, "__general_enum__", "Genral Enum Operations", "Genral Enum Operations");
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_enum_restore_default", L'⭯', 0);
+    p = la_SetGeneralRoot(&MAIN.GeneralEnumArraySub, "__general_enum_arr__", "Genral Enum Array Operations", "Genral Enum Array Operations");
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore the property to the original value", "LA_enum_array_restore_default", L'⭯', 0);
+    
+    p = la_SetGeneralRoot(&MAIN.GeneralStringSub, "__general_string__", "Genral String Operations", "Genral String Operations");
+    laAddOperatorProperty(p, "get_folder_path", "Get Folder Path", "Get a folder path", "LA_string_get_folder_path", L'📁', 0);
+    laAddOperatorProperty(p, "get_file_path", "Get File Path", "Get a file path", "LA_string_get_file_path", L'🖹', 0);
+    laAddOperatorProperty(p, "copy", "Copy", "Copy to clipboard", "LA_string_copy", 0, 0);
+    laAddOperatorProperty(p, "paste", "Paste", "Paste from clipboard", "LA_system_paste", 0, 0);
+    laAddOperatorProperty(p, "restore", "Restore Default", "Restore Default Value", "LA_string_set_default", L'⭯', 0);
+    p->UiDefine=laui_StringPropUiDefine;
+
+    p = la_SetGeneralRoot(&MAIN.GeneralOperatorSub, "__general_operator__", "Genral Operator Operations", "Genral Operator Operations");
+
+    p = la_SetGeneralRoot(&MAIN.GeneralCollectionSub, "__general_collection__", "Genral Collection Operations", "Genral Collection Operations");
+    laAddOperatorProperty(p, "put_data_block", "Put", "Append Pending Data Block Here", "LA_sub_put_data_block", L'🔗', 0);
+    laAddOperatorProperty(p, "save_instance", "Save Instance", "Save instance as a udf block", "LA_udf_save_instance", 0, 0);
+}
+
+void la_RegisterInternalProps(){
+    laPropContainer *p, *ip, *p2, *ip2, *sp1, *sp2;
+    laProp *ep;
+    laPropPack pp;
+    laSubProp *sp;
+    laKeyMapper *km;
+    laCanvasTemplate *v2dt;
+
+    {
+
+        la_UDFAppendSharedTypePointer("_LA_ROOT_NODE_", &MAIN);
+        la_UDFAppendSharedTypePointer("_TNS_ROOT_NODE_", T);
+
+        // THEME ==================================================================================================
+        {
+            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);
+
+            laAddSubGroup(p, "windows", "Windows", "All Registered Windows Of This Application", "ui_window",0, 0, 0, -1, laget_FirstWindow, laget_ActiveWindow, laget_ListNext, 0, 0, 0, 0, 0);
+            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);
+            laAddSubGroup(p, "la","LA", "LA Main Structure", "la_main",0, 0, laui_SubPropInfoDefault, -1, laget_Main, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE | LA_UDF_LOCAL);
+
+            p = laAddPropertyContainer("boxed_theme", "Boxed Theme", "A Single Theme Item For One Or Multiple Kinds Of UiItems", 0, laui_BoxedThemeItem, sizeof(laBoxedTheme), 0, 0, 1);{
+                laAddStringProperty(p, "name", "Name", "Boxed Theme Name", 0, 0, 0, 0, 1, offsetof(laBoxedTheme, Name), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+                laAddFloatProperty(p, "margins", "Margins", "Margins On Four Sides", 0, "Left,Right,Top,Bottom", 0, 1, -1, 0.05, 1, 0, offsetof(laBoxedTheme, Margins), 0, 0, 4, 0, laset_ThemeMargins, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "paddings", "Paddings", "Paddings On Four Sides", 0, "Left,Right,Top,Bottom", 0, 1, -1, 0.05, 1, 0, offsetof(laBoxedTheme, Paddings), 0, 0, 4, 0, laset_ThemePaddings, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "normal", "Normal", "Background brightness", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laBoxedTheme, NormalY), 0, laset_ThemeNormal, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "active", "Active", "Background brightness in active state", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laBoxedTheme, ActiveY), 0, laset_ThemeActive, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "border", "Border", "Border brightness", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laBoxedTheme, BorderY), 0, laset_ThemeBorder, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "text", "Text", "Text brightness", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laBoxedTheme, TextY), 0, laset_ThemeText, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "text_active", "Text Active", "Text brightness in active state", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laBoxedTheme, TextActiveY), 0, laset_ThemeTextActive, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "alpha", "Alpha", "Background alpha", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laBoxedTheme, Alpha), 0, laset_ThemeAlpha, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddSubGroup(p, "back_ref", "Back Ref", "Boxed theme internal back-ref", "any_pointer",0, 0, 0, offsetof(laBoxedTheme, BackRef), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+                laAddSubGroup(p, "parent", "Parent", "Parent Theme", "theme",0, 0, 0, offsetof(laBoxedTheme, Parent), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            }
+
+            p = laAddPropertyContainer("theme", "Theme Package", "A Package With ALl Types Of Theme For Ui Items", 0, laui_Theme, sizeof(laTheme), 0, 0, 2);{
+                laAddStringProperty(p, "name", "Name", "Theme Name", 0, 0, 0, 0, 1, offsetof(laTheme, Name), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+                laAddStringProperty(p, "author", "Author", "The Author's Name", 0, 0, 0, 0, 1, offsetof(laTheme, Author), 0, 0, 0, 0, 0);
+                laAddSubGroup(p, "boxed_themes", "Boxed Themes", "The Boxed Theme For Single UiItem Or Panel", "boxed_theme",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laTheme, BoxedThemes), 0);
+                laAddFloatProperty(p, "color", "Color", "Base color of the theme", LA_WIDGET_FLOAT_COLOR, "R,G,B,A", 0, 1, 0, 0.025, 1, 0, offsetof(laTheme, Color), 0, 0, 4, 0, 0, 0, 0, laset_ThemeColor, 0, 0, 0);
+                laAddFloatProperty(p, "accent_color", "Accent Color", "Theme accent color for hightlight etc", LA_WIDGET_FLOAT_COLOR, "R,G,B,A", 0, 1, 0, 0.025, 1, 0, offsetof(laTheme, AccentColor), 0, 0, 4, 0, 0, 0, 0, laset_ThemeAccentColor, 0, 0, 0);
+                laAddFloatProperty(p, "inactive_saturation", "Inactive Saturation", "Reduced saturation on inactive widgets", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laTheme, InactiveSaturation), 0, 0, 1, 0, 0, 0, 0, laset_ThemeInactiveSaturation, 0, 0, 0);
+                laAddFloatProperty(p, "inactive_mix", "Inactive Mix", "Reduced alpha on inactive widgets", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laTheme, InactiveMix), 0, 0, 1, 0, 0, 0, 0, laset_ThemeInactiveMix, 0, 0, 0);
+                laAddFloatProperty(p, "cursor_alpha", "Cursor Alpha", "Transparency of the cursor", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laTheme, CursorAlpha), 0, 0, 1, 0, 0, 0, 0, laset_ThemeCursorAlpha, 0, 0, 0);
+                laAddFloatProperty(p, "selection_alpha", "Selection Alpha", "Transparency of selection backgrounds", 0, 0, 0, 1, 0, 0.025, 1, 0, offsetof(laTheme, SelectionAlpha), 0, 0, 1, 0, 0, 0, 0, laset_ThemeSelectionAlpha, 0, 0, 0);
+                laAddFloatProperty(p, "wire_transparency", "Wire Transparency", "Alpha of the wire color", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, WireTransparency), 0, laset_ThemeWireTransparency, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "wire_saturation", "Wire Saturation", "Saturation of the wires", 0, 0, 0, 1, 0, 0.05, 0.8, 0, offsetof(laTheme, WireSaturation), 0, laset_ThemeWireSaturation, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "wire_brightness", "Wire Brightness", "Brightness of the wires", 0, 0, 0, 1, 0, 0.05, 0.8, 0, offsetof(laTheme, WireBrightness), 0, laset_ThemeWireBrightness, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "edge_transparency", "Edge Transparency", "Transparency of the edge color", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, EdgeTransparency), 0, laset_ThemeEdgeTransparency, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "edge_brightness", "Edge Brightness", "Brightness of the edge color", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, EdgeBrightness), 0, laset_ThemeEdgeBrightness, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "vertex_transparency", "Edge Transparency", "Transparency of the vertex color", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, VertexTransparency), 0, laset_ThemeVertexTransparency, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "vertex_brightness", "Edge Brightness", "Brightness of the vertex color", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, VertexBrightness), 0, laset_ThemeVertexBrightness, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "svertex_transparency", "Selected Vertex Transparency", "Transparency of selected vertices", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, SelectedVertexTransparency), 0, laset_ThemeSVertexTransparency, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "sedge_transparency", "Selected Edge Transparency", "Transparency of selected edges", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, SelectedEdgeTransparency), 0, laset_ThemeSEdgeTransparency, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+                laAddFloatProperty(p, "sface_transparency", "Selected Face Transparency", "Transparency of selected faces", 0, 0, 0, 1, 0, 0.05, 0.7, 0, offsetof(laTheme, SelectedFaceTransparency), 0, laset_ThemeSFaceTransparency, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+                laAddOperatorProperty(p, "delete", "Delete", "Delete this theme", "LA_delete_theme", 0, 0);
+            }
+        }
+
+        // TIME INFO =========================================================================================
+
+        p = laAddPropertyContainer("time_info", "Time Info", "Time Information Y/M/D/H/M/S", L'🕒', 0, sizeof(laTimeInfo), 0, 0, 0);{
+            laAddIntProperty(p, "year", "Year", "Year Value", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TimeYear, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "month", "Month", "Month Value", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TimeMonth, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "day", "Day", "Day Value", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TimeDay, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "hour", "Hour", "Hour Value", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TimeHour, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "minute", "Minute", "Minute Value", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TimeMinute, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "second", "Second", "Second Value", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TimeSecond, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddStringProperty(p, "time_string", "Time String", "Full String In \"Y-M-D H:M:S\" Format", 0, 0, 0, 0, 0, 0, 0, laget_TimeString, 0, 0,LA_READ_ONLY);
+        }
+
+        // LA MAIN =========================================================================================
+
+        p = laAddPropertyContainer("la_main", "LA Root", "LA Root Structure", L'🖴', 0, sizeof(LA), 0, 0, 2|LA_PROP_OTHER_ALLOC);{
+            laAddSubGroup(p, "logs", "Logs", "Application logs", "la_log",0, 0, laui_LogItem, -1, 0, 0, 0, 0, 0, 0, offsetof(LA, Logs), LA_UDF_IGNORE|LA_READ_ONLY);
+            laAddSubGroup(p, "differences", "Differences", "Difference stack (for undo/redo)", "la_difference",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(LA, Differences), LA_UDF_IGNORE|LA_READ_ONLY);
+            
+            _LA_PROP_WINDOW=laAddSubGroup(p, "windows", "Windows", "All Windows Under LA Control", "ui_window",0, 0, 0, offsetof(LA, CurrentWindow), laget_FirstWindow, 0, laget_ListNext, 0, 0, 0, offsetof(LA, Windows), 0);
+            la_UDFAppendSharedTypePointer("_LA_PROP_WINDOW", _LA_PROP_WINDOW);
+            laAddSubGroup(p, "data", "Data", "Data Root Control", "property_container",0, 0, 0, offsetof(LA, DataRoot.Root), 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddSubGroup(p, "prop_containers", "Sub Type", "Sub Type Property Container", "property_container",0, 0, 0, -1, laget_FirstContainer, 0, laget_ListNext, 0, 0, 0, 0, 0);
+            laAddSubGroup(p, "managed_props", "Managed Props", "Managed properties for saving", "managed_prop",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(LA, ManagedSaveProps), LA_UDF_IGNORE|LA_READ_ONLY);
+            laAddSubGroup(p, "managed_udfs", "Managed UDFs", "Managed UDFs for saving", "managed_udf", 0, 0, laui_ManagedUDFOps, -1, 0, 0, 0, 0, 0, 0, offsetof(LA, ManagedUDFs), LA_UDF_IGNORE|LA_READ_ONLY);
+            laAddSubGroup(p, "user_preferences", "User Preference", "Kernel Settings For LA Main Structure", "la_user_preference",0, 0, 0, -1, laget_Main, 0, 0, 0, 0, 0, 0, LA_UDF_LOCAL);
+            laAddSubGroup(p, "panel_templates", "Panel Templates", "Panel templates used to create new panel", "panel_template",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(LA, PanelTemplates), 0);
+
+            laAddSubGroup(p, "themes", "Themes", "Themes Loded In The Program", "theme",0, 0, laui_Theme, -1, 0, laget_ActiveTheme, 0, laset_ActiveTheme, 0, 0, offsetof(LA,Themes), 0);
+
+            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);
+            
+            laAddStringProperty(p, "identifier", "Identifier", "Identifier", 0, 0, 0, 0, 0, 0, 0, laget_MainIdentifier, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddSubGroup(p, "test_ucn", "TEST UCN", "---", "udf_content_node",0, 0, 0, offsetof(LA, TEST_Link), 0, 0, 0, 0, 0, 0, 0, 0);
+            
+            laAddIntProperty(p, "example_int", "Example Integer", "Example integer", 0, 0, 0, 100, 0, 1, 50, 0, offsetof(LA, example_int), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddStringProperty(p, "example_string", "Example String", "Example string", 0, 0, 0, 0, 1, offsetof(LA,example_string), 0, 0, 0, 0, 0);
+
+            //_LA_PROP_NODE_GRAPH = laAddSubGroup(p, "Node Graphs", "All node graphs in manage", "node_item",0, 0, 0, 0, 0, 0, laget_List2Next, 0, 0, 0, 0, 0, offsetof(LA, NodeGraphs), 0);
+        }
+        //p = laAddPropertyContainer("udf_fail_node", "UDF Failed Node", "Single Wild Data Block Reference", laui_UDFFailNodeItem, sizeof(laUDFFailNode), 0, 0, 0, 0, 0); {
+        //	laAddSubGroup(p, "instance", "Instance", "Actual Data Block Instance", "property_trash_item",0, 0, 0 Item.p), 0, 0, 0, 0, 0, 0, 0, 0,
+        //		0, 0,
+        //		0);
+        //	laAddSubGroup(p, "target_container", "Target Container", "The Container The Data Block Belongs To", "property_container",0, 0, 0 pc), 0, 0, 0, 0, 0, 0, 0, 0,
+        //		0, 0,
+        //		0);
+        //}
+        
+        p = laAddPropertyContainer("la_difference", "Difference", "A difference stack item (undo/redo).", 0, laui_IdentifierOnly, sizeof(laDiff), 0, 0, 1);{
+            laAddStringProperty(p, "description", "Description", "Description of this recorded change", LA_WIDGET_STRING_PLAIN, 0, 0, 0, 1, offsetof(laDiff, Description), 0, 0, 0, 0, LA_READ_ONLY|LA_AS_IDENTIFIER);
+        }
+
+        p = laAddPropertyContainer("la_log", "Resource Folder", "A resource folder to search for UDF references.", 0, laui_ResourceFolderItem, sizeof(laLogEntry), 0, 0, 1);{
+            laAddStringProperty(p, "content", "Content", "Content of the log", LA_WIDGET_STRING_PLAIN, 0, 0, 0, 1, offsetof(laLogEntry, Content), 0, 0, 0, 0, LA_READ_ONLY);
+        }
+
+        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", L'❌', 0);
+        }
+
+        p = laAddPropertyContainer("managed_udf", "Managed UDF", "Managed UDF files", L'🖹', laui_ManagedUDFItem, sizeof(laManagedUDF), 0, 0, 0);{
+            laAddStringProperty(p, "basename", "Base Name", "Base name of the file (withiout directory)", 0, 0, 0, 0, 1, offsetof(laManagedUDF, BaseName), 0, 0, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddSubGroup(p, "udf", "UDF", "Reference to target UDF file", "udf",0, 0, 0, offsetof(laManagedUDF, udf), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        }
+        p = laAddPropertyContainer("udf", "UDF File", "UDF file block", L'🖹', 0, sizeof(laUDF), 0, 0, 0);{
+            laAddStringProperty(p, "path", "Path", "File Path", 0, 0, 0, 0, 1, offsetof(laUDF, FileName), 0, 0, 0, 0, LA_READ_ONLY);
+            ep=laAddEnumProperty(p, "modified", "Modified", "File modified", LA_WIDGET_ENUM_ICON_PLAIN,0,0,0,0,offsetof(laUDF, Modified),0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+            laAddEnumItemAs(ep, "MODIFIED", "Modified", "There are unsaved changes bound to this file", 1, L'🌑');
+            laAddEnumItemAs(ep, "CLEAN", "Clean", "File data is untouched", 0, 0);
+            ep->ElementBytes=2;
+        }
+
+        p = laAddPropertyContainer("udf_content_node", "UDF Content Node", "Type Structure For Previewing,Selecting,Linking UDF Contnet", L'🖹', 0, 0, 0, 0, 0);{
+            laAddStringProperty(p, "full_path", "Full Path", "Full Path", 0, 0, 0, 0, 0, 0, 0, laget_UDFContentNodeFullPath, 0, 0,LA_READ_ONLY);
+            laAddStringProperty(p, "identifier", "Identifier", "Self Identifier", 0, 0, 0, 0, 0, 0, 0, laget_UDFContentNodeIdentifier, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddIntProperty(p, "file_seek", "File Seek", "Prop Beginner's Location In The File", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laUDFContentNode, FileSeek), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddSubGroup(p, "instances", "Instances", "Instance Nodes (Only SubProps)", "udf_content_instance",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laUDFContentNode, Instances), 0);
+            laAddSubGroup(p, "parent", "Parent", "Parent Instance Node", "udf_content_node",0, 0, 0, offsetof(laUDFContentNode, Parent), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "pc", "Prop Container", "This Property Container", "property_package",0, 0, 0, offsetof(laUDFContentNode, PP), 0, 0, 0, 0, 0, 0, 0, LA_UDF_LOCAL | LA_UDF_REFER);
+        }
+
+        p = laAddPropertyContainer("udf_content_instance", "UDF Content Instance", "Instance/FileSeek Storage For Previewing,Selecting,Linking UDF Contnet", L'🖹', 0, 0, 0, 0, 0);{
+            laAddStringProperty(p, "identifier", "Identifier", "Self Identifier", 0, 0, 0, 0, 0, 0, 0, laget_UDFContentInstanceIdentifier, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "file_seek", "File Seek", "Instance's Location In The File", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laUDFContentInstance, FileSeek), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddSubGroup(p, "children", "Children", "Child Properties (Only SubProps)", "udf_content_node",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laUDFContentInstance, Children), 0);
+            laAddSubGroup(p, "parent", "Parent", "Parent Property Node", "udf_content_node",0, 0, 0, offsetof(laUDFContentInstance, Parent), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        }
+        
+        p = laAddPropertyContainer("managed_prop", "Managed Property", "Managed property for detecting changes for saving files", 0, 0, sizeof(laManagedSaveProp), 0, 0, 0);{
+            laAddStringProperty(p, "path", "Path", "Property path", 0, 0, 0, 0, 1, offsetof(laManagedSaveProp, Path), 0, 0, 0, 0, LA_READ_ONLY);
+        }
+
+        p = laAddPropertyContainer("int_property", "Int Property", "Int property specific info", L'i', laui_IntPropInfo, sizeof(laIntProp), 0, 0, 1);{
+            laAddIntProperty(p, "range", "Range", "Range of the property", 0, "Min,Max", 0, 0, 0, 0, 0, 0, offsetof(laIntProp, Min), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "default", "Default", "Default value", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laIntProp, DefVal), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "step", "Step", "Ui step of the value", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laIntProp, Step), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddSubGroup(p, "base", "Base", "Property Base", "property_item", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE|LA_UDF_LOCAL);
+        } MAIN.ContainerInt = p;
+
+        p = laAddPropertyContainer("float_property", "Float Property", "Float property specific info", L'i', laui_FloatPropInfo, sizeof(laFloatProp), 0, 0, 1);{
+            laAddFloatProperty(p, "range", "Range", "Range of the property", 0, "Min,Max", 0, 0, 0, 0, 0, 0, offsetof(laFloatProp, Min), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddFloatProperty(p, "default", "Default", "Default value", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laFloatProp, DefVal), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddFloatProperty(p, "step", "Step", "Ui step of the value", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laFloatProp, Step), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddSubGroup(p, "base","Base", "Property Base", "property_item", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE|LA_UDF_LOCAL);
+        } MAIN.ContainerFloat = p;
+
+        // USER PREF ========================================================
+
+        p = laAddPropertyContainer("la_user_preference", "User Preference", "Kernel settings for LA main structure", L'⚙', 0, sizeof(LA), 0, 0, 2|LA_PROP_OTHER_ALLOC);{
+            laAddFloatProperty(p, "idle_time", "Idle time", "Time out on no input to show tooltips", 0, 0, 0, 2.0, 0.3, 0.05, 0.75, 0, offsetof(LA, IdleTime), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "top_framerate", "Top Framerate", "Framerate limiter for drawing the user interface", 0, 0, 0, 60, 25, 1, 60, 0, offsetof(LA, TopFramerate), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "valuator_threshold", "Valuator Threshold", "Drag How Many Pixels Trigger A Change In Valuator", 0, 0, 0, 10, 1, 1, 3, 0, offsetof(LA, ValuatorThreshold), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "scroll_speed", "Scrolling Speed", "How Many Pixels To Move When Scrolling Using Mouse Wheel", 0, 0, 0, 10, 1, 1, 3, 0, offsetof(LA, ScrollingSpeed), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddFloatProperty(p, "animation_speed", "Animation Speed", "Ui Animation Speed", 0, 0, 0, 0.6, 0.1, 0.05, 0.2, 0, offsetof(LA, AnimationSpeed), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddFloatProperty(p, "panel_animation_speed", "Panel Animation Speed", "Panel Animation Speed", 0, 0, 0, 0.6, 0.1, 0.05, 0.2, 0, offsetof(LA, PanelAnimationSpeed), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddFloatProperty(p, "zoom_speed_2d", "Zoom Speed 2D", "2D Canvas Zooming Speed", 0, 0, 0, 0.5, 0.01, 0.01, 0.01, 0, offsetof(LA, ZoomSpeed2D), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "tooltip_close_distance", "Tooltip Close Distance", "The tooltip will hide if mouse moved away further", 0, 0, 0, 100, 0, 1, 40, 0, offsetof(LA, TooltipCloseDistance), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            ep = laAddEnumProperty(p, "panel_multisample", "Panel Multisample", "Multisample mode for drawing panels", 0, 0, 0, 0, 0, offsetof(LA, PanelMultisample), 0, laset_PanelMultisample, 0, 0, 0, 0, 0, 0, 0, 0);{
+                laAddEnumItemAs(ep, "none", "None", "Don't use multisample", 0,0);
+                laAddEnumItemAs(ep, "2", "2X", "2X multisample", 2, 0);
+                laAddEnumItemAs(ep, "4", "4X", "4X multisample", 4, 0);
+                laAddEnumItemAs(ep, "8", "8X", "8X multisample", 8, 0);
+                laAddEnumItemAs(ep, "16", "16X", "16X multisample", 16, 0);
+            }
+            
+            laAddFloatProperty(p, "margin_size", "Margin Size", "The global margin factor", 0, 0, 0, 2.0f, 0.1f, 0.02, 1.0f, 0, offsetof(LA, MarginSize), 0, laset_MarginSize, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddFloatProperty(p, "font_size", "Font Size", "The height of the font related to the row height", 0, 0, 0, 1.0f, 0.1f, 0.02, 0.75, 0, offsetof(LA, FontSize), 0, laset_FontSize, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "interface_size", "Interface Size", "The height of one row of UI item", 0, 0, 0, 64, 16, 1, 40, 0, offsetof(LA, UiRowHeight), 0, laset_UiRowHeight, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+            laAddFloatProperty(p, "floating_alpha", "Shadow Alpha", "Shadow Transparency For Floating Panels", 0, 0, 0, 1, 0, 0.01, 0.7, 0, offsetof(LA, FloatingAlpha), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "solid_shadow_length", "Solid Shadow Length", "Solod Length For Floating Panels", 0, 0, 0, 40, 0, 1, 6, 0, offsetof(LA, SolidShadowLength), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "track_shadow_length", "Track Shadow Length", "Solod Length For Displaying Tracks", 0, 0, 0, 100, 0, 1, 30, 0, offsetof(LA, TrackShadowLength), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "wire_color_slices", "Wire color slices ", "How many slices of color to give to node sockets", 0, 0, 0, 32, 1, 1, 16, 0, offsetof(LA, WireColorSlices), 0, laset_WireColorSlices, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddFloatProperty(p, "wire_thickness", "Wire thickness", "How thick is a wire", 0, 0, 0, 10, 0.1, 0.5, 5, 0, offsetof(LA, WireThickness), 0, laset_WireThickness, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddFloatProperty(p, "wire_saggyness", "Wire saggyness", "How saggy is a wire", 0, 0, 0, 20, 0, 0.5, 5, 0, offsetof(LA, WireSaggyness), 0, laset_WireSaggyness, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+
+            ep = laAddEnumProperty(p, "enable_translation", "Enable Translation", "Translate user interface into another language", 0, 0, 0, 1, 0, offsetof(LA, Translation.EnableTranslation), 0, transState, 0, 0, 0, 0, 0, 0, 0, 0);{
+                laAddEnumItem(ep, "no", "No", "Use original english string", L'🗩');
+                laAddEnumItem(ep, "yes", "Yes", "Use translated string", 0);
+            }
+            laAddSubGroup(p, "languages", "Language", "The language list in the software", "la_translation_language",0, 0, laui_IdentifierOnly, offsetof(LA, Translation.CurrentLanguage), 0, 0, 0, 0, 0, 0, offsetof(LA, Translation.Languages), 0);
+            
+            laAddSubGroup(p, "resource_folders", "Resource Folders", "Folders to search for resources", "la_resource_folder",0,0,0, -1, 0, 0, 0, 0, 0, 0, offsetof(LA, ResourceFolders), 0);
+            ep = laAddEnumProperty(p, "manager_default_view", "UDF Manager Default View", "Prefer to show data blocks or files when saving", 0, 0, 0, 0, 0, offsetof(LA, ManagerDefaultView), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+                laAddEnumItemAs(ep, "DATA_BLOCKS", "Data Blocks", "All data blocks", 0, 0);
+                laAddEnumItemAs(ep, "FILES", "Files", "All Files", 1, 0);
+            }
+        }
+
+        p = laAddPropertyContainer("la_translation_language", "Language", "Translation language pack", 0, 0, sizeof(laTranslationNode), 0, 0, 2);{
+            laAddStringProperty(p, "name", "Name", "The name of this language", 0, 0, 0, "Unknown", 1, offsetof(laTranslationNode, LanguageName), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+        }
+
+        // UI WINDOW ========================================================================================
+
+        p = laAddPropertyContainer("ui_window", "Window Node", "Property Container For A System Window", 0, laui_SubPropInfoDefault, sizeof(laWindow), lapost_Window, 0, 2);{
+            laAddStringProperty(p, "title", "Title", "The Title/Name Of A Panel", 0, 0, 0, 0, 1, offsetof(laWindow, Title), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            laAddSubGroup(p, "layouts", "Layouts", "Layout List Of The Whole Window", "ui_layout",0, 0, 0, offsetof(laWindow, CurrentLayout), laget_WindowFirstLayout, 0, laget_ListNext, 0, 0, laset_WindowActiveLayout, offsetof(laWindow, Layouts), 0);
+            _LA_PROP_PANEL = laAddSubGroup(p, "panels", "Panels", "Panel list of this window", "ui_panel",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laWindow, Panels), 0);
+            la_UDFAppendSharedTypePointer("_LA_PROP_PANEL", _LA_PROP_PANEL);
+            laAddSubGroup(p, "maximized_block", "Maximized Block", "Maximized block in this window", "ui_block",0, 0, 0, offsetof(laWindow, MaximizedBlock), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "maximized_ui", "Maximized Ui", "Maximized ui in this window", "ui_item",0, 0, 0, offsetof(laWindow, MaximizedUi), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "panels_hidden", "Hidden Panels", "Hidden panels of this window", "ui_panel",0, 0, 0, -1, laget_FirstHiddenPanel, 0, laget_NextHiddenPanel, laset_WindowHiddenPanel, 0, 0, 0, LA_UDF_IGNORE);
+            laAddIntProperty(p, "position", "Position", "The Position Of A Window", 0, "X,Y", "px", 0, 0, 1, 0, 0, offsetof(laWindow, X), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "size", "Size", "The Size Of A Window", 0, "W,H", "px", 0, 0, 0, 0, 0, offsetof(laWindow, W), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "client_size", "Client Area Size", "Display Canvans Size Of A Window", 0, "W,H", "px", 0, 0, 1, 0, 0, offsetof(laWindow, CW), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddStringProperty(p, "operator_hints", "Operator Hints", "Operator hints if there's any", LA_WIDGET_STRING_PLAIN, 0, 0, 0, 1, offsetof(laWindow, OperatorHints), 0, 0, 0, 0, LA_READ_ONLY);
+        }
+
+        // UI LAYOUT ========================================================================================
+
+        p = laAddPropertyContainer("ui_block", "Layout Node", "Property Container For Single Layout", 0, laui_LayoutListItem, sizeof(laBlock), 0, 0, 0);{
+            laAddIntProperty(p, "location", "Location", "Block Location", 0, "X,Y", "px", 0, 0, 1, 0, 0, offsetof(laBlock, X), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "size", "Size", "Block Size", 0, "W,H", "px", 0, 0, 1, 0, 0, offsetof(laBlock, W), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddFloatProperty(p, "split_ratio", "Split Ratio", "Split Ratio On Two Subs", 0, 0, 0, 1, 0, 0.05, 0.5, 0, offsetof(laBlock, SplitRatio), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "vertical", "Vertical", "Is Vertival Or Not", 0, 0, 0, 1, 0, 1, 0, 0, offsetof(laBlock, Vertical), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddSubGroup(p, "panel_list", "Panel List", "Panels Under This Block", "ui_panel",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laBlock, Panels), 0);
+            laAddSubGroup(p, "current_panel", "Current Panel", "Current Selected Tab Panel", "ui_panel",0, 0, 0, offsetof(laBlock, CurrentPanel), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "sub1", "Sub 1", "Sub Block 1", "ui_block",0, 0, 0, offsetof(laBlock, B1), 0, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE);
+            laAddSubGroup(p, "sub2", "Sub 2", "Sub Block 2", "ui_block",0, 0, 0, offsetof(laBlock, B2), 0, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE);
+            laAddOperatorProperty(p, "fold", "Fold", "Fold the title bar", "LA_block_fold_title", 0, 0);
+            laAddOperatorProperty(p, "maximize", "Maximize", "Maximize the block", "LA_block_maximize", 0, 0);
+        }
+
+        p = laAddPropertyContainer("ui_layout", "Layout Node", "Property Container For Single Layout", 0, laui_LayoutListItem, sizeof(laLayout), 0, 0, 2);{
+            laAddStringProperty(p, "title", "Title", "The Title/Name Of A Panel", 0, 0, 0, 0, 1, offsetof(laLayout, ID), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            _LA_PROP_BLOCK = laAddSubGroup(p, "root_block", "Root Block", "Root Block For Panel Docking", "ui_block",0, 0, 0, offsetof(laLayout, FirstBlock), 0, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE);
+            la_UDFAppendSharedTypePointer("_LA_PROP_BLOCK", _LA_PROP_BLOCK);
+        }
+
+        // UI PANEL =========================================================================================
+
+        p = laAddPropertyContainer("ui_panel", "Panel Node", "Property Container For General Panels", 0, laui_PanelListItem, sizeof(laPanel), lapost_Panel, 0, 1);{
+            laAddStringProperty(p, "title", "Title", "The Title/Name Of A Panel", 0, 0, 0, 0, 1, offsetof(laPanel, Title), 0, 0, laset_PanelTitle, 0, LA_AS_IDENTIFIER);
+            laAddIntProperty(p, "position", "Position", "The Position Of A Panel", 0, "X,Y", "px", 0, 0, 1, 0, 0, offsetof(laPanel, X), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "size", "Size", "The Size Of A Panel", 0, "Width,Height", "px", 0, 0, 1, 0, 0, offsetof(laPanel, W), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "real_xywh", "Real Placemnt", "Placeent Data In Structure", 0, "X,Y,W,H", "px", 0, 0, 1, 0, 0, offsetof(laPanel, TX), 0, 0, 4, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            ep = laAddEnumProperty(p, "snap_enable", "Snap Enable", "Enable Snapping To Edges", 0, "Left,Right,Top,Bottom", 0, 0, 0, 0, 0, 0, 4, 0, laset_PanelSnapEnable, laget_PanelSnapEnable, 0, 0, 0, 0);{
+                laAddEnumItem(ep, "no", "No Snap", "Not Snapped to edge", 0);
+                laAddEnumItem(ep, "yes", "Snap", "Snapped to edge", L'🞉');
+            } //don't swap order with the one below
+            laAddIntProperty(p, "snap", "Snap Distance", "Snapping Distance To Edges", 0, "Left,Right,Top,Bottom", "px", 0, 0, 1, 0, 0, offsetof(laPanel, SL), 0, 0, 4, 0, laset_PanelSnapDistance, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "show", "Show", "The Panel Is Shown Or Not", 0, 0, 0, 0, 0, 1, 0, 0, offsetof(laPanel, Show), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            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", L'❌');
+                laAddEnumItem(ep, "true", "IsTrue", "Is A Menu Panel", L'🗩');
+            }
+            laAddOperatorProperty(p, "hide", "Hide", "Hide this panel", "LA_hide_panel", L'🗕', 0);
+            laAddOperatorProperty(p, "dock", "Dock", "Dock this panel", "LA_dock_panel", L'🗖', 0);
+            laAddOperatorProperty(p, "close", "Close", "Close this panel", "LA_block_close_panel", L'❌', 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, 0);
+            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, 0);
+            laAddSubGroup(p, "pp","Prop Pack", "Panel Base With Own Instance", "property_package",0, 0, 0, offsetof(laPanel, PP), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "fake_pp","Fake Prop Pack", "Fake Prop Pack", "property_package",0, 0, 0, offsetof(laPanel, PropLinkPP), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "parent_block","Parent Block", "The Block That Directly Links This Panel In", "ui_block",0, 0, 0, offsetof(laPanel, Block), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        }
+
+        // UI ITEM ==========================================================================================
+
+        p = laAddPropertyContainer("ui_list", "Ui List", "Property Container For Ui List Sub Type", L'⮑', 0, sizeof(laUiList), 0, 0, 0);{
+            laAddStringProperty(p, "tab_name", "Tab Name", "The Name Of A Tab", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            _LA_PROP_UI_ITEM = laAddSubGroup(p, "ui_items", "Ui Items", "Ui Items Listed In Ui List", "ui_item",0, 0, 0, -1, laget_FirstUiItem, 0, laget_ListNext, 0, 0, 0, offsetof(laUiList, UiItems), 0);
+            la_UDFAppendSharedTypePointer("_LA_PROP_UI_ITEM", _LA_PROP_UI_ITEM);
+            laAddSubGroup(p, "column_items", "Column Items", "Ui Items Listed In Ui List", "ui_column",0, 0, 0, -1, laget_FirstColumnItem, 0, 0, 0, 0, 0, offsetof(laUiList, Columns), 0);
+            laAddIntProperty(p, "pan", "Pan", "Cavans Panning Pixels", 0, "Pan X,Pan Y", "px", 10000, 0, 1, 0, 0, offsetof(laUiList, PanX), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddSubGroup(p, "instance", "Instance", "Collection Instance For Every Item", "ui_instance",0, 0, 0, offsetof(laUiList, Instance), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+
+            laAddIntProperty(p, "height_coeff", "Height Coefficiency", "How Many Rows A Ui Should Take Or Reserve", 0, 0, "Rows", 0, 0, 1, 0, 0, offsetof(laUiList, HeightCoeff), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+                ->ElementBytes = 2;
+            laAddIntProperty(p, "icon_id", "Icon ID", "Icon ID For This Ui List", 0, 0, "#", 1800, 32, 1, 0, 0, offsetof(laUiList, IconID), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+                ->ElementBytes = 2;
+        }
+        p = laAddPropertyContainer("ui_instance", "Instance", "UiList Instance Entry", L'🗇', 0, sizeof(laColumn), 0, 0, 0);{
+            //nothing needed
+        }
+        p = laAddPropertyContainer("ui_column", "Ui Column", "A Column Handles The Aligning Of Ui Items", L'◫', laui_IdentifierOnly, sizeof(laColumn), 0, 0, 0);{
+            laAddFloatProperty(p, "split_at", "Split At", "Split Width Percentage From Left", 0, 0, 0, 1, 0, 0.01, 0.5, 0, 0, laget_ColumnSP, laset_ColumnSP, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_IGNORE);
+            laAddFloatProperty(p, "real_split", "Real Split", "Float Value Split Pos In Real Strucutre", 0, 0, 0, 1, 0, 0.01, 0.5, 0, offsetof(laColumn, SP), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "snap_width", "Snap Width", "Snap Width Of A Column", 0, 0, 0, 200, 20, 1, 30, 0, 0, laget_ColumnSnap, laset_ColumnSnap, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_IGNORE);
+            laAddIntProperty(p, "real_snap", "Real Snap", "Int Snap Value In Real Structure", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laColumn, MaxW), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            ep = laAddEnumProperty(p, "snap_state", "Sub Snap State", "How To Snap Sub Columns", 0, 0, 0, 0, 0, 0, laget_SnapState, laset_SnapState, 0, 0, 0, 0, 0, 0, 0, LA_UDF_IGNORE);{
+                laAddEnumItem(ep, "none", "None", "No Snapping", 0);
+                laAddEnumItem(ep, "left", "Left", "Snap At Left", L'⮄');
+                laAddEnumItem(ep, "right", "Right", "Snap At Right", L'⮆');
+            }
+            laAddSubGroup(p, "left", "Left Sub Column", "Left Sub Column", "ui_column",0, 0, 0, offsetof(laColumn, LS), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "right", "Right Sub Column", "Right Sub Column", "ui_column",0, 0, 0, offsetof(laColumn, RS), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "self", "Self", "Self Display", "ui_column",0, LA_WIDGET_COLUMN_VIEWER, 0, -1, laget_Self, 0, 0, 0, 0, 0, 0, LA_UDF_REFER | LA_AS_IDENTIFIER);
+        }
+        p = laAddPropertyContainer("panel_template", "Panel Template", "Panel template for creating new panels", 0, 0, sizeof(laUiTemplate), 0, 0, 0);{
+            laAddStringProperty(p, "identifier", "Identifier", "Identifier Of This Template", 0, 0, 0, 0, 1, offsetof(laUiTemplate, Identifier), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            laAddStringProperty(p, "title", "Title", "Panel title", 0, 0, 0, 0, 1, offsetof(laUiTemplate, Title), 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "define_func", "Define Func", "Define Function Distinguish(Internal Only)", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laUiTemplate, Define), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_IGNORE|LA_READ_ONLY);
+        }
+
+        p = laAddPropertyContainer("ui_item", "Ui Item", "Property Container For Ui Items", 0, 0, sizeof(laUiItem), lapost_UiItem, lapostim_UiItem, 0);{
+            laAddIntProperty(p, "location", "Location", "The Ui's Location In A UiList(Prop For Live Edit Only)", 0, "Up", "Down", 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            laAddIntProperty(p, "state", "State", "The Ui's Internal State", 0, 0, 0, 0, 0, 1, 0, 0, offsetof(laUiItem, State), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "column_layout", "Column Layout", "The Ui's Column Layout", 0, 0, 0, 10, -10, 1, 0, 0, offsetof(laUiItem, SymbolID), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+                ->ElementBytes = sizeof(short);
+            //ep = laAddEnumProperty(p, "type", "Type", "The Type Of This Ui Item", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_IGNORE);{
+            //    laAddEnumItemAs(ep, "button", "Button", "Button (Pure Operator)", LA_UI_INTERNAL_BUTTON, L'🔨');
+            //    laAddEnumItemAs(ep, "property_watcher", "Property Watcher", "Property Watcher For Int/Float/Enum", LA_UI_INTERNAL_WATCHER, L'🔑');
+            //    laAddEnumItemAs(ep, "group", "Group", "A Group That Holds A Sub-UiList", LA_UI_INTERNAL_GROUP, L'📁');
+            //    laAddEnumItemAs(ep, "tab", "Tab", "A Tab Root That Holds Multiple Sub-UiList", LA_UI_INTERNAL_TAB, L'📑');
+            //    laAddEnumItemAs(ep, "label", "Label", "A Static Label", LA_UI_INTERNAL_LABEL, 0);
+            //    laAddEnumItemAs(ep, "3d_view", "3D View", "Integrated 3D View UI Item", LA_UI_INTERNAL_3D_VIEW, 0);
+            //    laAddEnumItemAs(ep, "2d_view", "2D View", "Integrated 2D View UI Item", LA_UI_INTERNAL_2D_VIEW, L'🖻');
+            //    laAddEnumItemAs(ep, "column_adjuster", "Column Adjuster", "To Adjust Column Width", LA_UI_INTERNAL_ADJUSTER, L'↔');
+            //    laAddEnumItemAs(ep, "bracket_begin", "Bracket Begin", "Bracket Beginner Used To Set Ui Conditions", LA_UI_INTERNAL_BRACKET_BEGIN, '{');
+            //    laAddEnumItemAs(ep, "bracket_else", "Bracket Else", "Bracket Else Block Beginner", LA_UI_INTERNAL_BRACKET_ELSE, 0);
+            //    laAddEnumItemAs(ep, "folder_begin", "Folder Begin", "Folder Beginner Used To Toggle Some Display", LA_UI_INTERNAL_FOLDER_BEGIN, '{');
+            //    laAddEnumItemAs(ep, "bracket_end", "Bracket End", "Bracket Closer", LA_UI_INTERNAL_BRACKET_END, '}');
+            //    laAddEnumItemAs(ep, "aligner", "Aligner", "Align Column Heights", LA_UI_INTERNAL_ALIGNER, 0);
+            //    laAddEnumItemAs(ep, "menu", "Menu", "Menu Activiator", LA_UI_INTERNAL_MENU, L'🗩');
+            //}
+            laAddStringProperty(p, "path", "Path", "Data Path", 0, 0, 0, 0, 0, 0, 0, laget_UiDataPath, 0, laread_UiDataPath,LA_READ_ONLY);
+            laAddStringProperty(p, "actuator_id", "Operator ID", "Pure Operator With No 'This' Pointer", 0, 0, 0, 0, 0, 0, 0, laget_UiOperatorID, 0, laread_UiOperatorID,LA_READ_ONLY);
+            laAddSubGroup(p, "pp", "Prop Pack", "Property Package In ui->PP Entry", "property_package",0, 0, 0, offsetof(laUiItem, PP), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "extra_pp", "Extra Prop Pack", "Property Package In ui->ExtraPP Entry", "property_package",0, 0, 0, offsetof(laUiItem, ExtraPP), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "go", "Prop Step Go", "Go Entry (For Determin If This Is A Prop Or Not)", "property_step",0, 0, 0, offsetof(laUiItem, PP.Go), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER | LA_UDF_IGNORE);
+            laAddSubGroup(p, "raw_this", "Prop Raw This", "ui->PP.RawThis Entry", "property_package",0, 0, 0, offsetof(laUiItem, PP.RawThis), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            //ep = laAddSubGroup(p, "Ui Template", "A Template Used To Create Sub Ui", "ui_template",0, LA_WIDGET_COLLECTION_SELECTOR, 0, offsetof(laUiItem, Template), laget_PanelTemplate, 0, laget_ListNext, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            //laSubGroupDetachable(ep, laget_UiTemplate, laget_ListNext);
+            laAddSubGroup(p, "current_page", "Current Page", "Current Page In Sub Ui List", "ui_list",0, 0, 0, offsetof(laUiItem, Page), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "internal_type", "Ui Internal Type", "Ui Internal Type", "ui_type",0, 0, 0, offsetof(laUiItem, Type), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "on_column", "On Column", "Ui On Which Column", "ui_column",0, 0, 0, offsetof(laUiItem, C), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddSubGroup(p, "sub", "Sub UI", "Sub Ui Lists For Tabs And Collection", "ui_list",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laUiItem, Subs), 0);
+            laAddStringProperty(p, "extra_args", "Extra Arguments", "Extra Arguments For This Ui Item", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddStringProperty(p, "display", "Display", "Display String For Label", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            //laAddSubGroup(p, "Condition Ui Extra Data", "Condition Ui Extra Data For Linkage And Conditioning", "ui_condition_extra_data",0, 0, 0, offsetof(laUiItem, Extra), laget_ConditionerExtra, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            //laAddSubGroup(p, "2d_extra", "2D View Extra Data", "2D View Ui States And Modes Storage", 0,0, 0, 0, offsetof(laUiItem, Extra), laget_CanvasExtra, 0, 0, 0, 0, 0, 0, 0);
+            laAddOperatorProperty(p, "maximize", "Maximize", "Maximize this UI item", "LA_canvas_ui_maximize", 0, 0);
+        }
+
+        p = laAddPropertyContainer("ui_type", "Ui Type", "Ui Type Descriptor", 0, laui_IdentifierOnly, sizeof(laUiType), 0, 0, 0);{
+            laAddStringProperty(p, "identifier", "Identifier", "Identifier Of This Ui Type", 0, 0, 0, 0, 0, offsetof(laUiType, Identifier), 0, 0, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+        }
+
+        // NODE ================================================================================================
+
+        p = laAddPropertyContainer("la_out_socket", "Output Socket", "Output socket for nodes", 0, 0, sizeof(laNodeOutSocket), 0, 0, 1);{
+            laAddStringProperty(p, "label", "Label", "Socket's label", 0, 0, 0, 0, 1, offsetof(laNodeOutSocket, Label), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            laAddIntProperty(p, "data_type", "Data type", "User defined data type", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laNodeOutSocket, DataType), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+        } LA_PC_SOCKET_OUT = p;
+        p = laAddPropertyContainer("la_in_socket", "Input Socket", "Input socket for nodest", 0, 0, sizeof(laNodeInSocket), 0, 0, 1);{
+            laAddStringProperty(p, "label", "Label", "Socket's label", 0, 0, 0, 0, 1, offsetof(laNodeInSocket, Label), 0, 0, 0, 0, LA_AS_IDENTIFIER);
+            laAddSubGroup(p, "source", "Source", "Source socket", "la_out_socket",0, 0, offsetof(laNodeInSocket, Source), 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddIntProperty(p, "data_type", "Data type", "User defined data type", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laNodeInSocket, DataType), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            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);
+        } LA_PC_SOCKET_IN = p;
+
+        // PROPERTIES ==========================================================================================
+
+        p = laAddPropertyContainer("property_item", "Property Item", "Property Item For Data Types Like Int/Float/Enum/String/SubType", L'🔌', 0, sizeof(laProp), 0, 0, 1);{
+            laAddStringProperty(p, "identifier", "Identifier", "Property Unique Identifier", LA_WIDGET_STRING_PLAIN, 0, 0, 0, 0, 0, 0, laget_PropertyIdentifier, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddStringProperty(p, "name", "Name", "Property Display Name", 0, 0, 0, 0, 0, offsetof(laProp, Name), 0, 0, 0, 0,LA_READ_ONLY);
+            laAddStringProperty(p, "description", "Description", "Property Description", 0, 0, 0, 0, 0, offsetof(laProp, Description), 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "prop_type", "Property Type", "Property Type(Like Int/Float/Enunm/Sub)", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laProp, PropertyType), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+            laAddIntProperty(p, "icon_id", "Icon Id", "Icon ID For Current Container", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laProp, IconID), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddIntProperty(p, "sub_icon_id", "Icon Id", "Icon ID For Current Container", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_PropertySubContainerIconID, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddSubGroup(p, "sub", "Sub Type", "Sub Type Property Container", "property_container",0, 0, 0, offsetof(laProp, SubProp), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        }
+
+        p = laAddPropertyContainer("property_container", "Property Container", "Property Container For Some Property Items", L'🔌', 0, sizeof(laPropContainer), 0, 0, 1);{
+            laAddStringProperty(p, "identifier", "Identifier", "Property Unique Identifier", LA_WIDGET_STRING_PLAIN, 0, 0, 0, 0, offsetof(laPropContainer, Identifier), 0, 0, 0, 0, LA_AS_IDENTIFIER | LA_UDF_IGNORE|LA_READ_ONLY);
+            laAddStringProperty(p, "name", "Name", "Property Display Name", 0, 0, 0, 0, 0, offsetof(laPropContainer, Name), 0, 0, 0, 0, LA_UDF_IGNORE|LA_READ_ONLY);
+            laAddStringProperty(p, "description", "Description", "Property Description", 0, 0, 0, 0, 0, offsetof(laPropContainer, Name), 0, 0, 0, 0, LA_UDF_IGNORE|LA_READ_ONLY);
+            laAddIntProperty(p, "icon_id", "Icon Id", "Icon ID For Current Container", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(laPropContainer, IconID), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+            laAddSubGroup(p, "properties", "Properties", "Single Property", "property_item", laget_PropertyNodeType, 0, 0, -1, laget_PropertyItemFirst, laget_PropertyItemFirst, laget_PropertyItemNext, 0, 0, 0, 0, LA_UDF_IGNORE);
+            _LA_PROP_FAILED_ITEM = laAddSubGroup(p, "failed_nodes", "Failed Nodes", "Used To Store UDF Failed Nodes", "property_trash_item",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laPropContainer, FailedNodes), LA_UDF_IGNORE);
+            _LA_PROP_TRASH_ITEM = laAddSubGroup(p, "trash_bin", "Trash Bin", "Used To Store Unlinked Items", "property_trash_item",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(laPropContainer, TrashBin), LA_UDF_IGNORE);
+            laAddOperatorProperty(p, "restore_all", "Restore All", "Restore All Trash Items Or Failed Nodes To A User Selected Linkage", "LA_sub_restore_data_block", L'⭯', 0);
+        }
+
+        p = laAddPropertyContainer("property_trash_item", "Trash Item", "Single Trash Item", 0, 0, 0, 0, 0, 0);{
+            laAddIntProperty(p, "instance_int", "Instance", "Memory Address Of This Data Block (INT Represent)", 0, 0, 0, 0, 0, 0, 0, 0, 0, laget_TrashItemInstance, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+            laAddSubGroup(p, "instance", "Instance", "Single Memory Address Of This Data Block", "property_trash_item",0, 0, 0, -1, 0, laget_TrashItemInstance, 0, 0, 0, 0, 0, LA_UDF_REFER | LA_UDF_IGNORE);
+            laAddOperatorProperty(p, "restore", "Restore", "Restore Data Block To A User Selected Linkage", "LA_sub_restore_data_block", L'⭯', 0);
+        }
+
+        p = laAddPropertyContainer("property_package", "Property Package", "Property Package For Data Access (Mainly UI)", L'🔌', 0, sizeof(laPropPack), 0, 0, 0);{
+            laAddSubGroup(p, "last_step", "Last Step", "Last Prop Step(Segment)", "property_step",0, 0, 0, offsetof(laPropPack, LastPs), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER | LA_UDF_IGNORE);
+        }
+        p = laAddPropertyContainer("property_step", "Property Step", "Property Segment Item", 0, 0, sizeof(laPropStep), 0, 0, 0);{
+            laAddSubGroup(p, "property", "Property", "Property Reference", "property_item",0, 0, 0, offsetof(laPropStep, p), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        }
+        p = laAddPropertyContainer("detached_prop", "Detached Prop", "Detached Prop", L'🔌', 0, sizeof(laSubProp) + 48, lapost_DetachedProp, 0, 0);{
+            laAddSubGroup(p, "raw_this", "Raw This", "Raw This Pointer", "property_package",0, 0, 0, offsetof(laProp, DetachedPP.RawThis), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+            laAddStringProperty(p, "path", "Path", "Data Path", 0, 0, 0, 0, 0, 0, 0, laget_DetachedPropPath, 0, laread_DetachedPropPath, 0);
+            laAddStringProperty(p, "rename", "Rename", "Rename", 0, 0, 0, 0, 0, offsetof(laProp, Identifier), 0, 0, 0, laread_DetachedPropRename, 0);
+        }
+
+    }
+
+    // TNS WORLD ============================================================================================
+
+    p = laAddPropertyContainer("tns_main", "TNS Main", "Render Kernel Root Structure", 0, 0, sizeof(tnsMain), 0, 0, 2);{
+        laAddSubGroup(p, "world", "World", "World Descriptor", "tns_world",0, 0, 0, offsetof(tnsMain, World), 0, 0, 0, 0, 0, 0, 0, LA_UDF_SINGLE | LA_UDF_LOCAL);
+
+        sp = laAddSubGroup(p, "texture_list", "Texture List", "List Of All Textures Under TNS Management", "tns_texture",0, 0, 0, -1, 0, tnsget_PreviewTexture, 0, 0, 0, tnsset_PreviewTexture, offsetof(tnsMain, Textures), LA_UDF_IGNORE);
+        laSubGroupDetachable(sp, tnsget_detached_FirstTexture, laget_ListNext);
+
+        //laAddSubGroup(p, "Render Buffers", "Storing All Render Buffers In Current Program Instance", "tns_render_buffer",0, 0, 0, offsetof(tnsMain, ActiveRenderBuffer), 0, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsMain, RenderBuffers), 0);
+
+        laAddStringProperty(p, "identifier", "Identifier", "Identifier", 0, 0, 0, 0, 0, 0, 0, laget_TNSIdentifier, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+    }
+
+    p = laAddPropertyContainer("tns_texture", "TNS Texture Item", "A Texture Descriptor With GL Handle", 0, 0, sizeof(tnsTexture), 0, 0, 0);{
+        laAddIntProperty(p, "gl_handle", "OpenGL Handle", "OpenGL Handle Of This Texture", LA_WIDGET_INT_PLAIN, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsTexture, GLTexHandle), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_AS_IDENTIFIER|LA_READ_ONLY);
+        laAddIntProperty(p, "size", "Size", "Width And Height", 0, "Width,Height", "px", 0, 0, 0, 0, 0, offsetof(tnsTexture, Width), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);
+        ep = laAddEnumProperty(p, "internal_type", "Internal Type", "Internal bits type", LA_WIDGET_ENUM_CYCLE, 0, 0, 0, 0, offsetof(tnsTexture, GLTexBitsType), 0, 0, 0, 0, 0, 0, 0, 0, 0,LA_READ_ONLY);{
+            laAddEnumItemAs(ep, "rgba", "GL_RGBA", "GL_RGBA", GL_RGBA8,0);
+            laAddEnumItemAs(ep, "rgb", "GL_RGB", "GL_RGB", GL_RGB8,0);
+            laAddEnumItemAs(ep, "rg", "GL_RG", "GL_RG", GL_RG8,0);
+            laAddEnumItemAs(ep, "r", "GL_RED", "GL_RED", GL_R8,0);
+            laAddEnumItemAs(ep, "rgba32f", "GL_RGBA32F", "GL_RGBA32F", GL_RGBA32F,0);
+            laAddEnumItemAs(ep, "rgb32f", "GL_RGB32F", "GL_RGB32F", GL_RGB32F,0);
+            laAddEnumItemAs(ep, "rg32f", "GL_RG32F", "GL_RG32F", GL_RG32F,0);
+            laAddEnumItemAs(ep, "r32f", "GL_R32F", "GL_R32F", GL_R32F,0);
+            laAddEnumItemAs(ep, "rgba32i", "GL_RGBA32I", "GL_R32I", GL_RGBA32I,0);
+            laAddEnumItemAs(ep, "rgb32i", "GL_RGB32I", "GL_R32I", GL_RGB32I,0);
+            laAddEnumItemAs(ep, "rg32i", "GL_RG32I", "GL_R32I", GL_RG32I,0);
+            laAddEnumItemAs(ep, "r32i", "GL_R32I", "GL_R32I", GL_R32I,0);
+            laAddEnumItemAs(ep, "depth", "GL_DEPTH_COMPONENT32F", "GL_DEPTH_COMPONENT32F", GL_DEPTH_COMPONENT32F,0);
+        }
+        p->Template2D = la_GetCanvasTemplate(0, "la_CanvasDrawTexture");
+    }
+
+    p = laAddPropertyContainer("tns_world", "World", "3D World Structure", 0, 0, sizeof(tnsWorld), 0, 0, 2|LA_PROP_OTHER_ALLOC);{
+        sp = laAddSubGroup(p, "root_objects", "Root Objects", "List of all root objects", "tns_object",0, 0, 0, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsWorld, RootObjects), 0);
+        laSubGroupDetachable(sp, tnsget_detached_FirstRootObject, laget_ListNext);
+        sp = laAddSubGroup(p, "objects", "Objects", "List of all objects", "tns_object",tnsget_ObjectType, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(tnsWorld, AllObjects), 0);
+    }
+
+    p = laAddPropertyContainer("tns_child_object", "Child Object", "Child object linker", 0, 0, sizeof(laListItemPointer), 0, 0, 0);{
+        laAddSubGroup(p, "object", "Object", "Object link", "tns_object",tnsget_ObjectType, 0, 0, offsetof(laListItemPointer, p), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+    }
+
+    p = laAddPropertyContainer("tns_object", "Object", "3D Object Item", 0, 0, sizeof(tnsObject), tnspost_Object, 0, 2);{
+        laPropContainerExtraFunctions(p,0,0,tnspropagate_Object);
+        TNS_PC_OBJECT_GENERIC=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);
+        ep = laAddEnumProperty(p, "show", "Show", "Show object in the viewport", 0, 0, 0, 0, 0, offsetof(tnsObject, Show), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(ep, "false", "False", "False", L'🌔');
+            laAddEnumItem(ep, "true", "IsTrue", "IsTrue", L'🌑');
+        }
+        ep = laAddEnumProperty(p, "show_on_render", "Show On Render", "Show on render", 0, 0, 0, 0, 0, offsetof(tnsObject, ShowOnRender), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(ep, "false", "False", "False", L'🚫');
+            laAddEnumItem(ep, "true", "IsTrue", "IsTrue", L'📷');
+        }
+        ep = laAddEnumProperty(p, "type", "Type", "Object Type Like Mesh,Camera And Lamp", 0, 0, 0, 0, 0, offsetof(tnsObject, Type), 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_READ_ONLY);{
+            laAddEnumItemAs(ep, "EMPTY", "Empty", "Empty object, not rendered", 0, L'➕');
+            laAddEnumItemAs(ep, "CAMERA", "Camera", "Camera object, to render a scene", TNS_OBJECT_CAMERA, L'📷');
+            laAddEnumItemAs(ep, "LIGHT", "Lamp", "Lamp object, to illuminate the scene", TNS_OBJECT_LIGHT, 0);
+            laAddEnumItemAs(ep, "MESH", "Mesh", "Mesh object, made of verts/edges/faces", TNS_OBJECT_MESH, 0);
+        }
+        laAddFloatProperty(p, "location", "Location", "XYZ Location In Local Coordinates", 0, "X,Y,Z", 0, 0, 0, 0.1, 0, 0, offsetof(tnsObject, Location), 0, 0, 3, 0, tnsset_ObjectLocation, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "rotation", "Rotation", "Rotation In Local Coordinates", 0, "X,Y,Z", 0, 0, 0, 0, 0, 0, offsetof(tnsObject, Rotation), 0, 0, 3, 0, tnsset_ObjectRotation, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "scale", "Scale", "Local Uniform Scale", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsObject, Scale), 0, tnsset_ObjectScale, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "glocation", "Global Location", "Location in global coordinates", 0, "X,Y,Z", 0, 0, 0, 0.1, 0, 0, offsetof(tnsObject, GLocation), 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "grotation", "Global Rotation", "Rotation in global coordinates", 0, "X,Y,Z", 0, 0, 0, 0, 0, 0, offsetof(tnsObject, GRotation), 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "gscale", "Global Scale", "Global uniform scale", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsObject, GScale), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "global_mat", "Global Matrix", "Global transformation matrix", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsObject, GlobalTransform), 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, LA_READ_ONLY);
+        laAddFloatProperty(p, "local_mat", "Local Matrix", "Local transformation matrix", 0, 0, 0, 0, 0, 0, 0, 0, offsetof(tnsObject, SelfTransform), 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, LA_READ_ONLY);
+        ep = laAddEnumProperty(p, "rotation_mode", "Rotation Mode", "Rotation Mode Of This Object(e.g. XYZ/XZY/Quaternion...)", 0, 0, 0, 0, 0, offsetof(tnsObject, RotationMode), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(ep, "xyz", "XYZ", "XYZ Euler Mode", 0); laAddEnumItem(ep, "xzy", "XZY", "XZY Euler Mode", 0);
+            laAddEnumItem(ep, "yxz", "YXZ", "YXZ Euler Mode", 0); laAddEnumItem(ep, "yzx", "YZX", "YZX Euler Mode", 0);
+            laAddEnumItem(ep, "zxy", "ZXY", "ZXY Euler Mode", 0); laAddEnumItem(ep, "zyx", "ZYX", "ZYX Euler Mode", 0);
+            laAddEnumItem(ep, "quaternion", "Quaternion", "Quaternion Mode", 0);
+        }
+        laAddSubGroup(p, "parent", "Parent", "Object parent", "tns_object",0, 0, 0, offsetof(tnsObject, ParentObject), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        laAddSubGroup(p, "children", "Children", "The Children Of This Object", "tns_child_object",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(tnsObject, ChildObjects), 0);
+    }
+    p = laAddPropertyContainer("tns_mesh_object", "Mesh Object", "Mesh object", 0, 0, sizeof(tnsMeshObject), tnspost_Object, 0, 2);{
+        laPropContainerExtraFunctions(p,0,tnstouched_Object,tnspropagate_Object);
+        TNS_PC_OBJECT_MESH=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);
+        ep = laAddEnumProperty(p, "mode", "Mode", "Mesh object mode", 0, 0, 0, 0, 0, offsetof(tnsMeshObject, Mode), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItemAs(ep, "OBJECT", "Object", "Object mode", TNS_MESH_OBJECT_MODE, 0);
+            laAddEnumItemAs(ep, "EDIT", "Edit", "Edit mode", TNS_MESH_EDIT_MODE, 0);
+        }
+        laAddSubGroup(p, "mv", "MMesh Verts", "Vertices of editing mesh", "tns_mvert",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(tnsMeshObject, mv), 0);
+        laAddSubGroup(p, "me", "MMesh Edges", "Edges of editing mesh", "tns_medge",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(tnsMeshObject, me), 0);
+        laAddSubGroup(p, "mf", "MMesh Faces", "Faces of editing mesh", "tns_mface",0, 0, 0, -1, 0, 0, 0, 0, 0, 0, offsetof(tnsMeshObject, mf), 0);
+        laAddIntProperty(p, "totmv", "MVert Count", "Total MVert", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, totmv),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p, "totme", "MEdge Count", "Total MEdge", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, totme),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p, "totmf", "MFace Count", "Total MFace", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, totmf),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddRawProperty(p, "v", "Verts", "Verts", offsetof(tnsMeshObject, v), tnsget_MeshObjectVertSize, 0, 0, LA_READ_ONLY);
+        laAddRawProperty(p, "e", "Edges", "Edges", offsetof(tnsMeshObject, e), tnsget_MeshObjectEdgeSize, 0, 0, LA_READ_ONLY);
+        laAddRawProperty(p, "f", "Faces", "Faces", offsetof(tnsMeshObject, f), 0, tnsget_MeshObjectFaceRaw, tnsset_MeshObjectFaceRaw, LA_READ_ONLY);
+        laAddIntProperty(p, "totv", "Vert Count", "Total Vert", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, totv),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p, "tote", "Edge Count", "Total Edge", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, tote),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p, "totf", "Face Count", "Total Face", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, totf),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        //laAddIntProperty(p, "maxv", "Max Vert", "Max Vert count", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, maxv),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        //laAddIntProperty(p, "maxe", "Max Edge", "Max Edge count", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, maxe),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        //laAddIntProperty(p, "maxf", "Max Face", "Max Face count", 0,0,0,0,0,0,0,0,offsetof(tnsMeshObject, maxf),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+    }
+    p = laAddPropertyContainer("tns_camera", "Camera", "Camera object", L'📷', 0, sizeof(tnsCamera), 0, 0, 2);{
+        laPropContainerExtraFunctions(p,0,0,tnspropagate_Object);
+        TNS_PC_OBJECT_CAMERA=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);
+        ep = laAddEnumProperty(p, "camera_type", "Camera Type", "Type Of A Camera, Like Perspective Or Fisheye", 0, 0, 0, 0, 0, offsetof(tnsCamera, CameraType), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(ep, "PERSP", "Perspective", "Camera in linear perspective", 0);
+            laAddEnumItem(ep, "ORTHO", "Orthographic", "Camera in orthographic view", 0);
+        }
+        laAddFloatProperty(p, "fov", "FOV", "Field Of View", 0, 0, "^", rad(160), rad(1), rad(0.1), rad(60), 0, offsetof(tnsCamera, FOV), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_IS_RAD);
+        laAddFloatProperty(p, "depth_range", "Depth Range", "Depth Range To Map From 0 To 1", 0, "Near,Far", 0, 0, 0, 0.1, 0, 0, offsetof(tnsCamera, ZMin), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "focus_distance", "Focus Distance", "For Viewing Camera To Determin Zooming Center", 0, 0, 0, 0, 0, 0.1, 100, 0, offsetof(tnsCamera, FocusDistance), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(p, "orth_scale", "Scale", "Orthographical Camera Scale", 0, 0, "^^", 1000, 0.001, 0.1, 1, 0, offsetof(tnsCamera, OrthScale), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddOperatorProperty(p, "set_active", "Set Active", "Set this camera as the active one", "TNS_set_active_camera", 0, 0);
+    }
+    p = laAddPropertyContainer("tns_light", "Light", "Light object", L'🔅', 0, sizeof(tnsLight), 0, 0, 2);{
+        laPropContainerExtraFunctions(p,0,0,tnspropagate_Object);
+        TNS_PC_OBJECT_LIGHT=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);
+        ep = laAddEnumProperty(p, "unidirectional", "UniDirectional", "UniDirectional lighting", 0, 0, 0, 0, 0, offsetof(tnsLight, UniDirectional), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(ep, "NONE", "Perspective", "Camera in linear perspective", 0);
+            laAddEnumItem(ep, "orthographic", "Orthographic", "Camera in orthographic view", 0);
+        }
+    }
+
+    p = laAddPropertyContainer("tns_mvert", "MVert", "MMesh vert", 0, 0, sizeof(tnsMVert), 0, 0, 0);{
+        laAddFloatProperty(p, "p", "Position", "Position", 0, "X,Y,Z", 0,0,0,0,0,0, offsetof(tnsMVert, p),0,0,3,0,0,0,0,0,0,0,0);
+        laAddFloatProperty(p, "n", "Normal", "Normal", 0, "X,Y,Z", 0,0,0,0,0,0, offsetof(tnsMVert, n),0,0,3,0,0,0,0,0,0,0,0);
+        laAddIntProperty(p,"i","Index","Index",0,0,0,0,0,0,0,0,offsetof(tnsMVert, i),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsMVert, flags),0,0,0,0,0,0,0,0,0,0,0);
+        laAddSubGroup(p, "elink", "Edge Link", "Edge link", "tns_medge_link",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsMVert, elink),0);
+    }
+    p = laAddPropertyContainer("tns_medge", "MEdge", "MMesh edge", 0, 0, sizeof(tnsMEdge), 0, 0, 0);{
+        laAddIntProperty(p,"i","Index","Index",0,0,0,0,0,0,0,0,offsetof(tnsMEdge, i),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsMEdge, flags),0,0,0,0,0,0,0,0,0,0,0);
+        laAddSubGroup(p, "vl", "vl", "Left vert", "tns_mvert",0,0,0,offsetof(tnsMEdge, vl),0,0,0,0,0,0,0,LA_UDF_REFER);
+        laAddSubGroup(p, "vr", "vr", "Right vert", "tns_mvert",0,0,0,offsetof(tnsMEdge, vr),0,0,0,0,0,0,0,LA_UDF_REFER);
+        laAddSubGroup(p, "fl", "fl", "Left face", "tns_mface",0,0,0,offsetof(tnsMEdge, fl),0,0,0,0,0,0,0,LA_UDF_REFER);
+        laAddSubGroup(p, "fr", "fr", "Right face", "tns_mface",0,0,0,offsetof(tnsMEdge, fr),0,0,0,0,0,0,0,LA_UDF_REFER);
+    }
+    p = laAddPropertyContainer("tns_mface", "MFace", "MMesh face", 0, 0, sizeof(tnsMFace), 0, 0, 0);{
+        laAddIntProperty(p,"i","Index","Index",0,0,0,0,0,0,0,0,offsetof(tnsMFace, i),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY);
+        laAddIntProperty(p,"flags","Flags","Flags",0,0,0,0,0,0,0,0,offsetof(tnsMFace, flags),0,0,0,0,0,0,0,0,0,0,0);
+        laAddSubGroup(p, "l", "Loop", "Loop", "tns_loop",0,0,0,-1,0,0,0,0,0,0,offsetof(tnsMFace, l),0);
+        laAddIntProperty(p,"looplen","Loop Length","Loop length",0,0,0,0,0,0,0,0,offsetof(tnsMFace, looplen),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY)->ElementBytes=2;
+        laAddFloatProperty(p, "n", "Normal", "Normal", 0, "X,Y,Z", 0,0,0,0,0,0, offsetof(tnsMFace, n),0,0,3,0,0,0,0,0,0,0,0);
+        laAddFloatProperty(p, "gn", "Global Normal", "Global normal", 0, "X,Y,Z", 0,0,0,0,0,0, offsetof(tnsMFace, gn),0,0,3,0,0,0,0,0,0,0,0);
+        laAddFloatProperty(p, "c", "Center", "Center", 0, "X,Y,Z", 0,0,0,0,0,0, offsetof(tnsMFace, c),0,0,3,0,0,0,0,0,0,0,0);
+    }
+    p = laAddPropertyContainer("tns_medge_link", "MEdge Link", "MEdge Link", 0, 0, sizeof(laListItemPointer), 0, 0, 0);{
+        laAddSubGroup(p, "e", "Edge", "Edge", "tns_medge",0,0,0,offsetof(laListItemPointer, p),0,0,0,0,0,0,0,LA_UDF_REFER);
+    }
+    p = laAddPropertyContainer("tns_loop", "MFace Loop", "MFace Loop", 0, 0, sizeof(laListItemPointer), 0, 0, 0);{
+        laAddSubGroup(p, "e", "Edge", "Edge", "tns_medge",0,0,0,offsetof(laListItemPointer, p),0,0,0,0,0,0,0,LA_UDF_REFER);
+    }
+}

+ 1418 - 0
source/lagui/resources/la_templates.c

@@ -0,0 +1,1418 @@
+#include "../la_5.h"
+
+extern LA MAIN;
+extern struct _tnsMain *T;
+
+
+int laget_InstanceModified(void* instance);
+void laget_TimeString(laTimeInfo *ti, char *result, char** resultdirect);
+
+void laui_DefaultPropDetails(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn *c;
+    laUiItem *b;
+    c = laFirstColumn(uil);
+    laSafeString* s=0;
+
+    if(Extra&&Extra->EndInstance){ //button
+        laGeneralUiExtraData* ex=Extra->EndInstance;
+        laUiItem* ui=ex->ui;
+        if(This&&This->LastPs&&This->EndInstance){
+            laProp* p=This->LastPs->p; laPropContainer* pc=p->Container; void* inst=This->LastPs->UseInstance; 
+            char FullPath[256]={0}; la_GetPropPackFullPath(This, FullPath);
+            strSafePrint(&s,"%s", FullPath); if(ui->ExtraInstructions){ strSafePrint(&s,"(%s)", ui->ExtraInstructions->Ptr); }
+            laShowLabel(uil,c,p->Description,0,0);
+            laShowLabel(uil,c,s->Ptr,0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        }else{
+            laShowLabel(uil,c,ui->AT->Description,0,0);
+            strSafePrint(&s,"%s", ui->AT->Identifier); if(ui->ExtraInstructions){ strSafePrint(&s,"(%s)", ui->ExtraInstructions->Ptr); }
+            laShowLabel(uil,c,s->Ptr,0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+        }
+    }else{
+        if(!This || !This->LastPs){ laShowLabel(uil,c,"Can't access property details.",0,0); return; }
+
+        char FullPath[256]={0}; la_GetPropPackFullPath(This, FullPath);
+        laProp* p=This->LastPs->p; laPropContainer* pc=p->Container; void* inst=This->LastPs->UseInstance;
+
+        laShowLabel(uil,c,p->Description,0,0);
+        if(p->PropertyType==(LA_PROP_ENUM)||(LA_PROP_ARRAY|LA_PROP_ENUM)){
+            laEnumItem* ei=laGetEnumArrayIndexed(This,This->LastIndex);
+            if(ei){ strSafeSet(&s,0);strSafePrint(&s,"Current: %s", ei->Description);laShowLabel(uil,c,s->Ptr,0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT; }
+        }
+        laShowLabel(uil,c,FullPath,0,0)->Flags|=LA_TEXT_MONO|LA_UI_FLAGS_DISABLED;
+
+        if(inst && !pc->OtherAlloc){
+            laShowSeparator(uil,c); strSafeSet(&s,0); strSafePrint(&s,"[ %s ]", pc->Name?pc->Name:pc->Identifier, inst);
+            int Level=0; laMemNodeHyper* m=memGetHead(inst,&Level);
+
+            laListHandle* users=memGetUserList(inst);
+            if(users){ strSafePrint(&s," %d Users", lstCountElements(users)); }
+            laShowLabel(uil,c,s->Ptr,0,0)->Flags|=LA_TEXT_MONO;
+
+            if(Level==2){
+                strSafeSet(&s,0);strSafePrint(&s, m->NUID.String);
+                if(laget_InstanceModified(inst)){ strSafePrint(&s, " 🌑 Modified"); }else{ strSafePrint(&s, " Clean"); }
+                laShowLabel(uil,c,s->Ptr,0,0)->Flags|=LA_TEXT_MONO;
+                laget_TimeString(&m->TimeCreated, FullPath, 0); 
+                strSafeSet(&s,0); strSafePrint(&s, "Created at %s", FullPath);
+                laShowLabel(uil,c,s->Ptr,0,0)->Flags|=LA_TEXT_MONO;
+            }
+
+            if(m){
+                if(Level==2){
+                    laShowSeparator(uil,c);
+                    if(m->FromFile){
+                        //strSafeSet(&s,0); strSafePrint(&s,"File:\n%s", m->FromFile->BaseName);
+                        //laShowLabel(uil,c,s->Ptr,0,0);
+                        char safepath[256]; strEscapePath(safepath, m->FromFile->BaseName->Ptr);
+                        strSafeSet(&s,0); strSafePrint(&s,"la.managed_udfs@basename=%s.__self", safepath);
+                        laShowItemFull(uil,c,0,s->Ptr,0,0,laui_ManagedUDFItem,0)->Flags|=LA_UI_FLAGS_NO_GAP|LA_UI_FLAGS_NO_DECAL;
+                    }else{
+                        laShowLabel(uil,c,"<Not saved yet>",0,0)->Flags|=LA_UI_FLAGS_DISABLED;
+                    }
+                }
+            }
+            
+        }
+    }
+    strSafeDestroy(&s);
+}
+
+void laui_DefaultPropUiDefine(laUiList *uil, laPropPack *This, laPropPack *OperatorProps, laColumn *UNUSED, int context){
+    laColumn *c;
+    laProp *p, *gp;
+
+    if (OperatorProps && OperatorProps->LastPs){
+        c = laFirstColumn(uil);
+
+        gp = OperatorProps->LastPs->p;
+        for (p = gp->SubProp->Props.pFirst; p; p = p->Item.pNext){
+            laShowItem(uil, c, OperatorProps, p->Identifier);
+        }
+    }
+
+    if (!This || !This->LastPs) return;
+
+    c = laFirstColumn(uil);
+
+    gp = This->LastPs->p;
+    for (p = gp->SubProp->Props.pFirst; p; p = p->Item.pNext){
+        //la_ShowGeneralPropItem(uil, c, This, gp, p, 0, 0, 0);
+        laShowItem(uil, c, This, p->Identifier);
+    }
+}
+void laui_StringPropUiDefine(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn *c;
+    laProp *p, *gp;
+
+    if (!This || !This->LastPs) return;
+    c = laFirstColumn(uil);
+
+    gp = This->LastPs->p;
+
+    if(Extra){
+        laShowItem(uil, c, Extra, "copy_selection");
+    }else{
+        laShowItem(uil, c, This, "copy");
+    }
+    laShowItem(uil, c, This, "paste");
+    laShowItem(uil, c, This, "restore");
+    if(gp->Tag&LA_PROP_IS_FILE){ laShowItem(uil, c, This, "get_file_path"); }
+    if(gp->Tag&LA_PROP_IS_FOLDER){ laShowItem(uil, c, This, "get_folder_path"); }
+}
+
+void laui_IdentifierOnly(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context){
+    laColumn *col = Extra, *c, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiItem *ui;
+
+    c = laFirstColumn(uil);
+
+    laShowItemFull(uil, c, This, "identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+}
+
+void laui_SubShow(laPropPack *pp){
+    if (laGetInt(pp) & LA_PROP_SUB) return 1;
+    return 0;
+}
+void laRebuildPathRecursive(laProp *p, char *buf){
+    if (p->Container){
+        laRebuildPathRecursive(p->Container, buf);
+        sprintf(buf, ".%s", p->Identifier);
+    }else
+        sprintf(buf, "%s", p->Identifier);
+}
+
+void laui_IntPropInfo(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *ExtraColumns, int context){
+    laColumn *col, *cl, *cr;
+    laUiItem *b1,*b2;
+    laUiList *tuil;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.2);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+
+    laShowItemFull(uil, cr, Base, "base.identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+    b1= laOnConditionToggle(uil, cl, 0,0,0,0,0);{
+        for(laProp* p=MAIN.ContainerInt->Props.pFirst;p;p=p->Item.pNext){
+            laShowItem(uil,cr,Base,p->Identifier);
+        }
+    }laEndCondition(uil,b1);
+}
+void laui_FloatPropInfo(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *ExtraColumns, int context){
+    laColumn *col, *cl, *cr;
+    laUiItem *b1,*b2;
+    laUiList *tuil;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.2);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+
+    laShowItemFull(uil, cr, Base, "base.identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+    b1= laOnConditionToggle(uil, cl, 0,0,0,0,0);{
+        for(laProp* p=MAIN.ContainerFloat->Props.pFirst;p;p=p->Item.pNext){
+            laShowItem(uil,cr,Base,p->Identifier);
+        }
+    }laEndCondition(uil,b1);
+}
+
+void laui_SubPropInfoDefault(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr, *crrl, *crrr;
+    laUiItem *bracket, *b1, *b2;
+    laPropContainer *pc;
+    laProp *p;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.2);
+    cl = laLeftColumn(c, 1);
+    cr = laRightColumn(c, 0);
+    laSplitColumn(uil, cr, 0.5);
+    crrl = laLeftColumn(cr, 1*6);
+    crrr = laRightColumn(cr, 0);
+
+    laPropContainer* subc=Base->LastPs->p->SubProp;
+    if (!((laSubProp*)Base->LastPs->p)->GetType){
+        if (!subc) subc = la_ContainerLookup(((laSubProp *)Base->LastPs->p)->TargetID);
+        if (!subc) return; Base->LastPs->p->SubProp=subc;
+    }else{
+        subc=((laSubProp*)Base->LastPs->p)->GetType(Base->EndInstance);
+    }
+
+    if (!Base->LastPs->p->UDFIsRefer && !Base->LastPs->p->UDFNoCreate && !Base->LastPs->p->UDFIsSingle){
+        laShowItem(uil, cr, Base, "identifier")->Flags|=LA_UI_FLAGS_PLAIN;
+        bracket = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);
+    }
+    for (p = subc->Props.pFirst; p; p = p->Item.pNext){
+        if (!(p->PropertyType & LA_PROP_SUB)){
+            buf[0] = 0;
+            sprintf(buf, "la.prop_containers#%s.properties#%s.name", p->Container->Identifier, p->Identifier);
+            laShowItemFull(uil, crrl, 0, buf, LA_WIDGET_STRING_PLAIN,0, 0, 0);
+            laShowItem(uil, crrr, Base, p->Identifier);
+            //buf[0] = 0; sprintf(buf, "la.prop_containers#%s.properties#%s.name", p->Container->Identifier, p->Identifier); laShowItemFull(uil, crl, 0, buf, 0, laui_SubPropInfoDefault, 0);
+            //buf[0] = 0; sprintf(buf, "la.prop_containers#%s.properties#%s.description", p->Container->Identifier, p->Identifier); laShowItemFull(uil, crr, 0, buf, 0, laui_SubPropInfoDefault, 0);
+            laShowSeparator(uil, c);
+        }else{
+            //buf[0] = 0; sprintf(buf, "la.prop_containers#%s.properties#%s.name", p->Container->Identifier, p->Identifier); laShowItemFull(uil, crrl, 0, buf, LA_WIDGET_STRING_PLAIN, 0, 0);
+            //buf[0] = 0; sprintf(buf, "la.prop_containers#%s.properties#%s.name", p->Container->Identifier, p->Identifier); laShowItemFull(uil, crl, 0, buf, 0, laui_SubPropInfoDefault, 0);
+            //buf[0] = 0; sprintf(buf, "la.prop_containers#%s.properties#%s.description", p->Container->Identifier, p->Identifier); laShowItemFull(uil, crr, 0, buf, 0, laui_SubPropInfoDefault, 0);
+            if (p->UDFIsRefer) laShowLabel(uil, crrr, "🠞", 0, 0);
+            elif (p->UDFNoCreate) laShowLabel(uil, crrr, "n", 0, 0);
+            else laShowLabel(uil, crrr, "🗇", 0, 0);
+
+            buf[0] = 0;
+            sprintf(buf, "la.prop_containers#%s.icon_id", ((laSubProp *)p)->TargetID);
+            laShowIcon(uil, cl, 0, buf, 0);
+
+            b1 = laOnConditionToggle(uil, crrl, 0, 0, 0, 0, 0);{ b1->Flags|=LA_TEXT_ALIGN_LEFT;
+                sprintf(buf, "text=...%s;", p->Name);
+                strSafeSet(&b1->ExtraInstructions, buf);
+                laUiDefineFunc f=((laSubProp*)p)->GetType?0:
+                    (p->UiDefine?p->UiDefine:(p->SubProp&&p->SubProp->UiDefine?p->SubProp->UiDefine:laui_SubPropInfoDefault));
+                laShowItemFull(uil, cr, Base, p->Identifier, 0,0, f, 0);
+            }
+            laEndCondition(uil, b1);
+            laShowSeparator(uil, c);
+        }
+    }
+    if (!Base->LastPs->p->UDFIsRefer && !Base->LastPs->p->UDFNoCreate && !Base->LastPs->p->UDFIsSingle){
+        laEndCondition(uil, bracket);
+    }
+    //laShowItemFull(uil, crl, Base, "identifier", 0, 0, 0);
+    //p = Base->LastPs->p->SubProp->Props.pFirst;
+}
+void laui_SubPropSelection(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr, *crrl, *crrr;
+    laUiItem *bracket, *b1, *b2;
+    laPropContainer *pc;
+    laProp *p;
+    laPropPack *pp;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.2);
+    cl = laLeftColumn(c, 1);
+    cr = laRightColumn(c, 0);
+    laSplitColumn(uil, cr, 0.8);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 100);
+    laSplitColumn(uil, crl, 0.5);
+    crrl = laLeftColumn(crl, 150);
+    crrr = laRightColumn(crl, 0);
+
+    if (!Base->LastPs->p->SubProp) Base->LastPs->p->SubProp = la_ContainerLookup(((laSubProp *)Base->LastPs->p)->TargetID);
+
+    if (!Base->LastPs->p->UDFIsRefer){
+        laShowItemFull(uil, cr, Base, "identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+        bracket = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);
+    }
+
+    for (p = Base->LastPs->p->SubProp->Props.pFirst; p; p = p->Item.pNext){
+        if (p->PropertyType == LA_PROP_SUB){
+            //buf[0] = 0; sprintf(buf, "la.prop_containers#%s.properties#%s.name", p->Container->Identifier, p->Identifier);
+            //laShowItemFull(uil, crrl, 0, buf, LA_WIDGET_STRING_PLAIN, 0, 0);
+
+            buf[0] = 0;
+            sprintf(buf, "identifier=%s;", p->Identifier);
+            laShowItemFull(uil, crrr, Base, "put_data_block", 0, buf, 0, 0);
+
+            //laShowLabel(uil, crr, "PUT", 0, 0);
+            b1 = laOnConditionToggle(uil, crrl, 0, 0, 0, 0, 0);{
+                buf[0] = 0; sprintf(buf, "text=...%s;", p->Name); strSafeSet(&b1->ExtraInstructions, buf);
+                laShowItemFull(uil, cr, Base, p->Identifier, 0,0, laui_SubPropSelection, 0)->Flags|=LA_TEXT_ALIGN_LEFT;
+            }
+            laEndCondition(uil, b1);
+
+            laShowSeparator(uil, c);
+        }
+    }
+    if (!Base->LastPs->p->UDFIsRefer){
+        laEndCondition(uil, bracket);
+    }
+    //laShowItemFull(uil, crl, Base, "identifier", 0, 0, 0);
+    //p = Base->LastPs->p->SubProp->Props.pFirst;
+}
+
+void laui_LinkerSelectionProp(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr, *crrl, *crrr;
+    laUiItem *bracket, *b1, *b2;
+    laPropContainer *pc;
+    laProp *p;
+    laPropPack *pp;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.4);
+    cl = laLeftColumn(c, 1);
+    cr = laRightColumn(c, 0);
+
+    b1=laBeginRow(uil,cr,0,0);
+    laShowItemFull(uil, cr, Base, "identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+    laShowIcon(uil, cr, Base, "pp.last_ps.property.sub_icon_id", 0);
+    laEndRow(uil,b1);
+
+    bracket = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);{
+        laShowItemFull(uil, cr, Base, "instances", 0,0, laui_LinkerSelectionInstance, 0);
+    }
+    bracket->State=LA_BT_ACTIVE;
+    laEndCondition(uil, bracket);
+}
+void laui_LinkerSelectionInstance(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr, *crrl, *crrr;
+    laUiItem *bracket, *b1, *b2;
+    laPropContainer *pc;
+    laProp *p;
+    laPropPack *pp;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.4);
+    cl = laLeftColumn(c, 1);
+    cr = laRightColumn(c, 0);
+
+    laShowItemFull(uil, cr, Base, "identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+
+    b1 = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);{
+        laShowItemFull(uil, cr, Base, "children", 0,0, laui_LinkerSelectionProp, 0);
+    }
+    laEndCondition(uil, b1);
+}
+
+void laui_DefaultPanelTitleBar(laUiList *uil, laPropPack *Base, laPropPack *Extra, laUiDefineFunc header){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr, *cb1, *cb2, *cb3;
+    laUiItem *bracket, *b1, *b2;
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.3);
+    cl = laLeftColumn(c, 1);
+    cr = laRightColumn(c, 0);
+
+    b1=laBeginRow(uil,cr,0,0);
+    laShowItemFull(uil, cr, Base, "title", LA_WIDGET_STRING_PLAIN,0, 0, 0)->Expand=1;
+    laShowItem(uil, cr, Base, "hide")->Flags|=LA_UI_FLAGS_ICON;
+    laShowItem(uil, cr, Base, "dock")->Flags|=LA_UI_FLAGS_ICON;
+    laShowItem(uil, cr, Base, "close")->Flags|=LA_UI_FLAGS_ICON;
+    laEndRow(uil,b1);
+    bracket = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);{
+        if(!Extra->LastPs->p->SubProp->Props.pFirst){
+            laShowLabel(uil, cr, "Panel doesn't have configurable property.", 0, 0);
+        }else{
+            if(header){
+                laShowLabel(uil, cr, "Panel properties:", 0, 0);
+                header(uil, Base, Extra, cr, 0);
+            }else{
+                for(laProp* p = Extra->LastPs->p->SubProp->Props.pFirst;p;p=p->Item.pNext){
+                    laShowItem(uil, cr, Extra, p->Identifier);
+                }
+            }
+        }
+        //laShowItem(uil, cr, 0,"la.example_int");
+        laShowSeparator(uil, c);
+        //laShowLabel(uil, c, "Position:", 0, 0);
+        //laShowItemFull(uil, c, Base, "position", LA_WIDGET_INT, 0, 0);
+        //laShowLabel(uil, c, "Size:", 0, 0);
+        //laShowItemFull(uil, c, Base, "size", LA_WIDGET_INT, 0, 0);
+        //laShowLabel(uil, c, "Snapping:", 0, 0);
+        //laShowItem(uil, c, Base, "snap_enable")->Flags=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_TRANSPOSE;
+        //laShowItemFull(uil, c, Base, "snap", LA_WIDGET_INT, 0, 0);
+    }
+    laEndCondition(uil, bracket);
+}
+void laui_DefaultOperatorPanelTitleBar(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr;
+    laUiItem *bracket, *b1, *b2;
+
+    c = laFirstColumn(uil);
+
+    b1 = laBeginRow(uil,c,0,0);
+    laShowItemFull(uil, c, Base, "title", LA_WIDGET_STRING_PLAIN,0, 0, 0)->Expand=1;
+    laShowItem(uil, c, 0, "LA_cancel");//->Flags|=LA_UI_FLAGS_ICON;
+    laEndRow(uil, b1);
+}
+
+void laui_ColumnItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *c0, *c, *cl, *cr, *cll, *clr, *crl, *crr, *clll, *cllr, *cll2, *clr2;
+    laUiItem *bracket, *b1, *b2;
+
+    c0 = laFirstColumn(uil);
+    laSplitColumn(uil, c0, 0.8);
+    cll = laLeftColumn(c0, 80);
+    c = laRightColumn(c0, 0);
+    laSplitColumn(uil, c, 0.7);
+    cl = laLeftColumn(c, 0);
+    cr = laRightColumn(c, 200);
+    laSplitColumn(uil, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 70);
+
+    laSplitColumn(uil, cll, 0.5);
+    clll = laLeftColumn(cll, 1);
+    cllr = laRightColumn(cll, 0);
+
+    laSplitColumn(uil, cl, 0.5);
+    cll2 = laLeftColumn(cl, 0);
+    clr2 = laRightColumn(cl, 70);
+
+    //laShowItem(uil, c, Base, "self");
+
+    bracket = laOnConditionThat(uil, crr, laPropExpression(0, "live_editor.current_ui")); // laOnConditionThat(uil, 0, "live_editor", la_LiveEditAllowShow);
+    laShowItemFull(uil, cll, Base, "select_column", 0, "text=Select;", 0, 0);
+    laEndCondition(uil, bracket);
+
+    bracket = laOnConditionThat(uil, c, laPropExpression(Base, "sub_left"));{ //laOnConditionThat(uil, Base, 0, laui_SnapButtonShow); {
+        laShowItem(uil, cll2, Base, "split_at");
+        laShowItemFull(uil, clr2, Base, "merge_column", 0, "text=Merge;", 0, 0);
+
+        b1 = laOnConditionThat(uil, c, laPropExpression(Base, "snap_state"));{
+            laShowItem(uil, crl, Base, "snap_width");
+        }
+        laElse(uil, b1);{
+            laShowLabel(uil, crl, "Align:", 0, 0)->Flags|=LA_TEXT_ALIGN_RIGHT;
+        }
+        laEndCondition(uil, b1);
+
+        laShowItem(uil, crr, Base, "snap_state");
+
+        laShowSeparator(uil, c0);
+
+        b1 = laOnConditionToggle(uil, clll, 0, 0, 0, 0, 0);{
+            laShowItemFull(uil, c, Base, "sub_left", LA_WIDGET_COLLECTION_SINGLE,0, laui_ColumnItem, 0);
+        }
+        laElse(uil, b1);{
+            laShowLabel(uil, cllr, "Left", 0, 0);
+        }
+        laEndCondition(uil, b1);
+
+        laShowSeparator(uil, c0);
+
+        b1 = laOnConditionToggle(uil, clll, 0, 0, 0, 0, 0);{
+            laShowItemFull(uil, c, Base, "sub_right", LA_WIDGET_COLLECTION_SINGLE,0, laui_ColumnItem, 0);
+        }
+        laElse(uil, b1);{
+            laShowLabel(uil, cllr, "Right", 0, 0);
+        }
+        laEndCondition(uil, b1);
+    }
+    laElse(uil, bracket);{
+        laShowItem(uil, c, Base, "split_column");
+    }
+    laEndCondition(uil, bracket);
+}
+
+void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context){
+    laUiList *muil;
+    laColumn *c, *c1, *c1r, *c2, *c2r, *c3, *c3r, *c4, *c4r, *mc, *mcl, *mcr;
+    laUiItem* bb;
+
+    c = laFirstColumn(uil);
+    laUiItem* row=laBeginRow(uil,c,0,0);
+
+    bb=laOnConditionThat(uil,c,laPropExpression(0,"la.windows.operator_hints"));{
+        
+        laShowItem(uil,c,0,"la.windows.operator_hints");
+
+    }laElse(uil,bb);{
+        laShowItem(uil, c, 0, "LA_new_panel")->Flags=LA_UI_FLAGS_ICON;
+        muil = laMakeMenuPage(uil, c, "File");{
+            mc = laFirstColumn(muil);
+            laShowItem(muil, mc, 0, "TNS_load_exchange");
+
+            laShowLabel(muil, mc, "Function Test", 0, 0);
+            laShowItem(muil, mc, 0, "LA_pure_yes_no");
+            laShowItem(muil, mc, 0, "LA_file_dialog");
+            laShowItem(muil, mc, 0, "LA_udf_append");
+            laShowItem(muil, mc, 0, "LA_managed_save");
+            laShowItem(muil, mc, 0, "LA_manage_udf");
+
+            laShowLabel(muil, mc, "Other Entries", 0, 0);
+            laShowItemFull(muil, mc, 0, "LA_panel_activator", 0, "panel_id=LAUI_about;text=About;", 0, 0);
+            laShowItem(muil, mc, 0, "LA_terminate_program");
+        }
+        muil = laMakeMenuPage(uil, c, "Options"); {
+            mc = laFirstColumn(muil);
+            laShowLabel(muil, mc, "Settings", 0, 0);
+            laShowItemFull(muil, mc, 0, "LA_panel_activator", 0, "panel_id=LAUI_user_preferences;", 0, 0);
+        }
+
+        laShowSeparator(uil,c);
+
+        laUiItem* mui=laOnConditionThat(uil,c,laPropExpression(0,"la.windows.maximized_ui"));{
+            laShowItemFull(uil,c,0,"LA_canvas_ui_maximize", 0, "icon=🡰;restore=true;text=Restore Layout", 0, 0);
+        }laElse(uil,mui);{
+            laUiItem* ui=laOnConditionThat(uil,c,laPropExpression(0,"la.windows.maximized_block"));{
+                laShowItemFull(uil,c,0,"LA_block_maximize", 0, "icon=🡰;restore=true;text=Restore Layout", 0, 0);
+            }laElse(uil,ui);{
+                laShowItemFull(uil, c, 0, "LA_switch_layout", 0, "icon=🞐;show_list=true;", 0, 0)->Flags|=LA_UI_FLAGS_ICON;
+                laShowItemFull(uil,c,0,"LA_switch_layout", 0, "icon=🡰;reverse=true;", 0, 0)->Flags|=LA_UI_FLAGS_ICON;
+                laShowItemFull(uil,c,0,"LA_switch_layout", 0, "icon=🡲;", 0,0)->Flags|=LA_UI_FLAGS_ICON;
+                laShowItem(uil, c, 0, "la.windows.layouts.identifier");
+                laShowItem(uil,c,0,"LA_new_window")->Flags|=LA_UI_FLAGS_ICON;
+            }laEndCondition(uil, ui);
+        }laEndCondition(uil,mui);
+
+        laShowSeparator(uil,c);
+        laShowLabel(uil, c, "🧩LaGUI 2022", 0, 0)->Expand=1;
+
+        laUiItem* b1=laOnConditionThat(uil,c,laPropExpression(0,"la.windows.panels_hidden"));
+            laShowSeparator(uil,c);
+            muil = laMakeMenuPage(uil, c, "🡻 Minimized");{
+                mc = laFirstColumn(muil);
+                laShowItemFull(muil, mc, 0, "la.windows.panels_hidden", 0,0, laui_IdentifierOnly,0);
+            }
+        laEndCondition(uil, b1);
+
+    }laEndCondition(uil,bb);
+
+    laEndRow(uil,row);
+}
+void laui_DefaultMenuBar(laWindow *w){
+    laPanel *p;
+    laUiList *uil, *muil;
+    laColumn *c, *c1, *c1r, *c2, *c2r, *c3, *c3r, *c4, *c4r, *mc;
+    laUiItem *bracket;
+
+    p =laCreateTopPanel(w, 0, 0, 0, 0, LA_RH, 0, 0, 0, 0, -1, -1, -1, 0);
+    p->IsMenuPanel = 1;
+    laui_DefaultMenuBarActual(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0);
+}
+
+void laui_ThemeListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr;
+    laUiItem *bracket;
+
+    col = laFirstColumn(uil);
+
+    bracket = laBeginRow(uil,col,0,0);
+    laShowItemFull(uil, col, Base, "name", LA_WIDGET_STRING_PLAIN,0, 0, 0)->Expand=1;
+    laShowItemFull(uil, col, Base, "author", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+    laEndRow(uil,bracket);
+}
+void laui_Theme(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *cll, *clr;
+    laUiItem *sui;
+    laUiList *tuil;
+    laUiItem *ui;
+
+    //col = laFirstColumn(uil);
+    //tuil = laMakeGroup(uil, col, "����ժҪ", 0, 0)->Page; {
+    //	col = laFirstColumn(tuil);
+    //	laSplitColumn(tuil, col, 0.7);
+    //	cl = laLeftColumn(col, 0);
+    //	cr = laRightColumn(col, 0);
+    //	laSplitColumn(tuil, cr, 0.6);
+    //	crl = laLeftColumn(cr, 0);
+    //	crr = laRightColumn(cr, 70);
+    //	laShowItemFull(tuil, cl, 0, "themes.name", 0, 0, 0);
+    //	laShowItemFull(tuil, crl, 0, "themes.author", 0, 0, 0);
+    //	laShowLabel(tuil, crr, 0, "EXEC", 0, 0, 0);
+    //}
+
+    col = laFirstColumn(uil); laSplitColumn(uil,col,0.5);
+    cl=laLeftColumn(col,0);
+    cr=laRightColumn(col,0);
+
+    ui=laBeginRow(uil,col, 0,0);
+    laShowItem(uil,col,Base, "name")->Expand=1;
+    laShowItem(uil,col,Base, "delete");
+    laEndRow(uil, ui);
+
+    laShowLabel(uil, col, "Basics:",0,0);
+    laShowLabel(uil, cl, "Base Color:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT; laShowItem(uil, cr, Base, "color");
+    laShowLabel(uil, cl, "Accent Color:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT; laShowItem(uil, cr, Base, "accent_color");
+    laShowItem(uil, cr, Base, "cursor_alpha");
+    laShowItem(uil, cr, Base, "selection_alpha");
+    laShowItem(uil, cr, Base, "inactive_mix");
+    laShowItem(uil, cr, Base, "inactive_saturation");
+
+    laShowLabel(uil, col, "Nodes:",0,0);
+    laShowItem(uil, cr, Base, "wire_brightness");
+    laShowItem(uil, cr, Base, "wire_saturation");
+    laShowItem(uil, cr, Base, "wire_transparency");
+
+    laShowLabel(uil, col, "Meshes:",0,0);
+    laShowItem(uil, cl, Base, "edge_transparency");
+    laShowItem(uil, cl, Base, "edge_brightness");
+    laShowItem(uil, cr, Base, "vertex_transparency");
+    laShowItem(uil, cr, Base, "vertex_brightness");
+    laShowItem(uil, col, Base, "svertex_transparency");
+    laShowItem(uil, col, Base, "sedge_transparency");
+    laShowItem(uil, col, Base, "sface_transparency");    
+
+    laShowLabel(uil, col, "Widgets:",0,0);
+    laShowItem(uil, col, Base, "boxed_themes");
+}
+void laui_BoxedThemeItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *crl,*crr;
+    laUiItem *bracket;
+    laUiList *tuil;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.8);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+    laSplitColumn(uil, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+
+    laShowItemFull(uil, cr, Base, "name", LA_WIDGET_STRING_PLAIN, 0 ,0,0);
+
+    bracket = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);{
+        laShowItem(uil, cr, Base, "normal");
+        laShowItem(uil, cr, Base, "active");
+        laShowItem(uil, cr, Base, "border");
+        laShowItem(uil, cr, Base, "text");
+        laShowItem(uil, cr, Base, "text_active");
+        laShowItem(uil, cr, Base, "alpha");
+        laShowLabel(uil,crl,"Margins:",0,0);
+        laShowItem(uil, crl, Base, "margins")->Flags=LA_UI_FLAGS_TRANSPOSE;
+        laShowLabel(uil,crr,"Paddings:",0,0);
+        laShowItem(uil, crr, Base, "paddings")->Flags=LA_UI_FLAGS_TRANSPOSE;
+    }
+    laEndCondition(uil, bracket);
+}
+
+void laui_PropertyContainerList(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *crl, *crr, *cll, *clr, *crrl, *crrr;
+    laUiItem *bracket;
+    laUiList *tuil;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.5);
+    cl = laLeftColumn(col, 60);
+    cr = laRightColumn(col, 0);
+    laSplitColumn(uil, cr, 0.25);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+    laSplitColumn(uil, crr, 0.3);
+    crrl = laLeftColumn(crr, 0);
+    crrr = laRightColumn(crr, 0);
+
+    laShowLabel(uil, cl, "Select", 0, 0);
+    laShowLabel(uil, crl, "Identifier", 0, 0);
+    laShowLabel(uil, crrl, "Name", 0, 0);
+    laShowLabel(uil, crrr, "Description", 0, 0);
+    laShowColumnAdjuster(uil, col);
+
+    laShowItem(uil, col, Base, "properties");
+}
+void laui_WindowListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *cll, *clr;
+    laUiItem *bracket;
+    laUiList *tuil;
+
+    cl = laFirstColumn(uil);
+    laSplitColumn(uil, cl, 0.2);
+    cll = laLeftColumn(cl, 1);
+    clr = laRightColumn(cl, 0);
+
+    laShowItem(uil, clr, Base, "title");
+
+    bracket = laOnConditionToggle(uil, cll, 0, 0, 0, 0, 0);{
+        laShowLabel(uil, clr, "Layouts", 0, 0);
+        laShowItem(uil, clr, Base, "layouts");
+        laShowLabel(uil, clr, "TopPanels", 0, 0);
+        laShowItem(uil, clr, Base, "panels");
+    }
+    laEndCondition(uil, bracket);
+}
+void laui_LayoutListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *cll, *clr;
+    laUiItem *bracket;
+    laUiList *tuil;
+
+    cl = laFirstColumn(uil);
+    laSplitColumn(uil, cl, 0.2);
+    cll = laLeftColumn(cl, 1);
+    clr = laRightColumn(cl, 0);
+
+    laShowItem(uil, clr, Base, "title");
+
+    bracket = laOnConditionToggle(uil, cll, 0, 0, 0, 0, 0);{
+        laShowItem(uil, clr, Base, "panels");
+    }
+    laEndCondition(uil, bracket);
+}
+void laui_PanelListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *cll, *clr;
+    laUiItem *bracket;
+    laUiList *tuil;
+
+    cl = laFirstColumn(uil);
+    laSplitColumn(uil, cl, 0.2);
+    cll = laLeftColumn(cl, 1);
+    clr = laRightColumn(cl, 0);
+
+    laShowItem(uil, clr, Base, "title");
+
+    bracket = laOnConditionToggle(uil, cll, 0, 0, 0, 0, 0);{
+
+        laShowItemFull(uil, clr, Base, "size", LA_WIDGET_INT,0, 0, 0);
+    }
+    laEndCondition(uil, bracket);
+}
+void laui_UiTemplateListItemLiveEdit(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *cll, *clr;
+    laUiItem *bracket;
+    laUiList *tuil;
+
+    cl = laFirstColumn(uil);
+
+    //bracket = laOnConditionThat(uil, cl, laNot(laPropExpression(Base, "for_panel"))); {
+
+    bracket = laOnConditionThat(uil, cl, laAnd(laNot(laPropExpression(Base, "for_panel")), laOr(laNot(laPropExpression(Base, "target")), laEqual(laPropExpression(0, "live_editor.current_ui.prop_pack.last_ps.property.sub"), laPropExpression(Base, "target")))));{
+        laShowItemFull(uil, cl, Base, "identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+    }
+    laElse(uil, bracket);{
+        laShowItemFull(uil, cl, Base, "identifier", LA_WIDGET_STRING_PLAIN, "disabled=true;",0, 0);
+    }
+    laEndCondition(uil, bracket);
+}
+void laui_UiTemplateListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *cll, *clr, *clll, *cllr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiItem *bracket, *b1;
+    laUiList *tuil;
+
+    cl = laFirstColumn(uil);
+    laSplitColumn(uil, cl, 0.2);
+    cll = laLeftColumn(cl, LA_2RH);
+    clr = laRightColumn(cl, 0);
+
+    laSplitColumn(uil, cll, 0.5);
+    clll = laLeftColumn(cll, 0);
+    cllr = laRightColumn(cll, 0);
+
+    laSplitColumn(uil, clr, 0.5);
+    clrl = laLeftColumn(clr, 0);
+    clrr = laRightColumn(clr, 200);
+
+    laSplitColumn(uil, clrr, 0.2);
+    clrrl = laLeftColumn(clrr, 1);
+    clrrr = laRightColumn(clrr, 0);
+
+    bracket = laOnConditionThat(uil, cll, laPropExpression(Base, "define_func"));{
+        laShowLabel(uil, clll, "f", 0, 0);
+    }
+    laEndCondition(uil, bracket);
+
+    bracket = laOnConditionThat(uil, cll, laPropExpression(Base, "descriptor"));{
+        laShowLabel(uil, cllr, "🠞", 0, 0);
+    }
+    laEndCondition(uil, bracket);
+
+    laShowItemFull(uil, clrl, Base, "identifier", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+
+    bracket = laOnConditionThat(uil, cll, laPropExpression(Base, "target_id"));{
+        laShowIcon(uil, clrrl, Base, "target.icon_id", 0);
+        laShowItemFull(uil, clrrr, Base, "target_id", LA_WIDGET_STRING_PLAIN,0, 0, 0);
+    }
+    laElse(uil, bracket);{
+        b1 = laOnConditionThat(uil, cll, laPropExpression(Base, "for_panel"));{
+            //laShowLabel(uil, clrrl, 0,, 0, 0);
+            laShowLabel(uil, clrrr, "PANEL", 0, 0);
+        }
+        laElse(uil, b1);{
+            laShowLabel(uil, clrrr, "-", 0, LA_WIDGET_STRING_PLAIN);
+        }
+        laEndCondition(uil, b1);
+    }
+    laEndCondition(uil, bracket);
+}
+
+int la_CreateSystemWindow(laWindow *window);
+
+void tnsui_GroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *crl, *crr;
+    laUiItem *b1;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.3);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+    laSplitColumn(uil, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+
+    laShowItem(uil, cr, Base, "name");
+    b1 = laOnConditionToggle(uil, cl, 0, 0, 0, 0, 0);{
+        laShowItem(uil, cr, Base, "objects");
+    }
+    laEndCondition(uil, b1);
+}
+void tnsui_ObjectGroupItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *crl, *crr;
+    laUiItem *b1;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.3);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+    laSplitColumn(uil, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+
+    laShowItem(uil, cr, Base, "group.name");
+}
+void tnsui_GroupObjectItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *crl, *crr;
+    laUiItem *b1;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.3);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+    laSplitColumn(uil, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+
+    laShowItem(uil, cr, Base, "object.identifier");
+}
+void tnsui_MaterialItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
+    laColumn *col, *cl, *cr, *crl, *crr;
+    laUiItem *b1;
+
+    col = laFirstColumn(uil);
+    laSplitColumn(uil, col, 0.3);
+    cl = laLeftColumn(col, 1);
+    cr = laRightColumn(col, 0);
+    laSplitColumn(uil, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+
+    laShowItem(uil, cr, Base, "object.identifier");
+}
+
+void laui_PlainSceneListItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context){
+    laColumn *col = Extra, *c, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiItem *ui;
+
+    //if (Extra)c = Extra;
+
+    c = laFirstColumn(uil);
+
+    laShowItemFull(uil, c, This, "name", LA_WIDGET_STRING_PLAIN, 0, 0, 0);
+}
+
+void laui_DataRestorePage(laUiList *uil, laPropPack *THIS_UNUSED, laPropPack *Operator, laColumn *UNUSED, int context){
+    laColumn *col = laFirstColumn(uil), *c, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiList *u;
+    laUiItem *b;
+
+    laShowItemFull(uil, col, 0, "la", 0, 0, laui_SubPropSelection, 0);
+    laShowItemFull(uil, col, 0, "tns", 0, 0, laui_SubPropSelection, 0);
+}
+void laui_FileBrowserFileItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context){
+    laColumn *c = Extra, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiItem *ui;
+
+    laSplitColumn(0, c, 0.1);
+    cll = laLeftColumn(c, 30);
+    clr = laRightColumn(c, 0);
+    laSplitColumn(0, clr, 0.7);
+    clrl = laLeftColumn(clr, 0);
+    clrr = laRightColumn(clr, 0);
+    laSplitColumn(0, clrr, 0.5);
+    clrrl = laLeftColumn(clrr, 0);
+    clrrr = laRightColumn(clrr, 0);
+
+    laShowItemFull(uil, cll, This, "type", LA_WIDGET_ENUM_ICON_PLAIN, 0, 0, 0)->Flags|=LA_TEXT_ALIGN_RIGHT;
+    //laShowItem(uil, cll, This, "is_folder");
+    laShowItemFull(uil, clrl, This, "name", LA_WIDGET_STRING_PLAIN, 0, 0, 0);
+    ui = laOnConditionThat(uil, clrr, laNot(laPropExpression(This, "is_folder")));{
+        laShowItemFull(uil, clrrl, This, "time_modified.time_string", LA_WIDGET_STRING_PLAIN, 0, 0, 0);
+        laShowItem(uil, clrrr, This, "size")->Flags|=LA_UI_FLAGS_NO_DECAL;
+    }
+    laEndCondition(uil, ui);
+    //laShowSeparator(uil,cll)
+    //laShowItemFull(uil, clrrl, This, "time_modified.time_string", LA_WIDGET_STRING_PLAIN, 0, 0);
+    //laShowItem(uil, clrrr, This, "size");
+}
+void laui_FileBrowserDiskItem(laUiList *uil, laPropPack *This, laPropPack *OP_UNUSED, laColumn *Extra, int context){
+    laColumn *col = Extra, *c, *cl, *cr, *crl, *crr;
+    laUiItem *ui;
+
+    c = Extra;
+    laSplitColumn(0, c, 0.2);
+    cl = laLeftColumn(c, LA_2RH);
+    cr = laRightColumn(c, 0);
+    laSplitColumn(0, cr, 0.5);
+    crl = laLeftColumn(cr, 0);
+    crr = laRightColumn(cr, 0);
+    //laShowColumnAdjuster(uil, c);
+
+    laShowItemFull(uil, cl, This, "id", LA_WIDGET_STRING_PLAIN, 0, 0, 0);
+    laShowItem(uil, crl, This, "total_gb");
+    laShowItem(uil, crr, This, "free_gb");
+}
+void laui_FileBrowserFileList(laUiList *uil, laPropPack *THIS_UNUSED, laPropPack *Operator, laColumn *UNUSED, int context){
+    laColumn *col = laFirstColumn(uil), *c, *cl, *cr, *crl, *crr, *cll, *clr, *clrl, *clrr, *clrrl, *clrrr;
+    laUiList *u;
+    laUiItem *b;
+
+    laSplitColumn(uil, col, 0.25);
+    cl = laLeftColumn(col, 250);
+    cr = laRightColumn(col, 0);
+
+    laShowItem(uil, cr, Operator, "path");
+    laShowItemFull(uil, cl, Operator, "folder_up", LA_WIDGET_BUTTON_NO_CONFIRM, 0 ,0,0);
+
+    u = laMakeGroup(uil, cl, "Logic Drives", 0)->Page;
+    c = laFirstColumn(u);
+    laSplitColumn(u, c, 0.2);
+    cll = laLeftColumn(c, LA_2RH);
+    clr = laRightColumn(c, 0);
+    laSplitColumn(u, clr, 0.5);
+    clrl = laLeftColumn(clr, 0);
+    clrr = laRightColumn(clr, 0);
+    laShowColumnAdjuster(u, c);
+    laShowItem(u, c, Operator, "disk_list");
+
+    b = laMakeGroup(uil, cr, "File List", 0);b->State=LA_UI_ACTIVE; u=b->Page;
+    u->HeightCoeff = -3;
+    c = laFirstColumn(u);
+    laShowColumnAdjuster(u, c);
+    laSplitColumn(u, c, 0.1);
+    cll = laLeftColumn(c, 1);
+    clr = laRightColumn(c, 0);
+    laSplitColumn(u, clr, 0.7);
+    clrl = laLeftColumn(clr, 0);
+    clrr = laRightColumn(clr, 0);
+    laSplitColumn(u, clrr, 0.5);
+    clrrl = laLeftColumn(clrr, 0);
+    clrrr = laRightColumn(clrr, 0);
+    laShowLabel(u, clrl, "File Name", 0, 0);
+    laShowLabel(u, clrrl, "Last Modified On", 0, 0);
+    laShowLabel(u, clrrr, "File Size", 0, 0);
+    laShowItem(u, c, Operator, "file_list")->Flags|=LA_UI_FLAGS_NO_DECAL;
+
+    laShowSeparator(uil, cr);
+    laUiItem*r=laBeginRow(uil,cr,0,0);
+    laShowItem(uil, cr, Operator, "file_name")->Expand=1;
+    b = laOnConditionThat(uil, cl, laOr(laAnd(laEqual(laPropExpression(Operator, "select_what"), laIntExpression(LA_FILE_SELECT_FILE)), laPropExpression(Operator, "file_name")), laEqual(laPropExpression(Operator, "select_what"), laIntExpression(LA_FILE_SELECT_FOLDER))));{
+        laShowItem(uil, cr, 0, "LA_confirm")->Flags|=LA_UI_FLAGS_HIGHLIGHT;
+    }
+    laEndCondition(uil, b);
+    laEndRow(uil,r);
+}
+void laui_LinkerPanel(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *cll, *clr, *crl, *crr, *crrl, *crrr, *gc;
+    laUiList *gu;
+    laUiItem *bracket, *b1, *b2;
+    laPropContainer *pc;
+    laProp *p;
+    laPropPack *pp;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.2);
+    cl = laLeftColumn(c, 100);
+    cr = laRightColumn(c, 0);
+    laSplitColumn(uil, cr, 0.2);
+    crl = laLeftColumn(cr, 1);
+    crr = laRightColumn(cr, 0);
+
+    gu = laMakeGroup(uil, c, " UDF File Content", 0)->Page;{
+        gc = laFirstColumn(gu);
+        laShowItem(gu, gc, OperatorInst, "root_nodes");
+    }
+}
+
+void laui_ManagedUDFItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c=laFirstColumn(uil);
+    laSplitColumn(uil,c,0.5);
+    laColumn *cl=laLeftColumn(c, 1);
+    laColumn *cr=laRightColumn(c,0);
+    laUiItem* b2=laOnConditionThat(uil,cr,laPropExpression(Base,"udf"));{
+        laUiItem* r=laBeginRow(uil,c,0,0);
+        laUiItem* b=laOnConditionToggle(uil,c,0,0,0,0,0);strSafeSet(&b->ExtraInstructions,"text=🛈;");b->Flags|=LA_UI_FLAGS_PLAIN;{
+            laShowItemFull(uil,c,Base,"udf.path",LA_WIDGET_STRING_PLAIN, 0 ,0,0);
+        }laElse(uil,b);{
+            laShowItemFull(uil,c,Base,"basename",LA_WIDGET_STRING_PLAIN, 0 ,0,0);
+        }laEndCondition(uil,b);
+        laEndRow(uil, r);
+    }laElse(uil,b2);{
+        laShowItemFull(uil,c,Base,"basename",LA_WIDGET_STRING_PLAIN, 0 ,0,0);
+    }laEndCondition(uil,b2);
+}
+void laui_ManagedUDFOps(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c=laFirstColumn(uil);
+    laSplitColumn(uil,c,0.3);
+    laColumn *cl=laLeftColumn(c, 1);
+    laColumn *cr=laRightColumn(c,0);
+    laUiItem* b1=laOnConditionThat(uil, cr, laPropExpression(Base, "udf"));{
+        laShowItem(uil,cl,Base,"udf.modified");
+        laUiItem* b=laBeginRow(uil,cr,0,0);
+        laUiItem* b2=laOnConditionToggle(uil,cr,0,0,0,0,0);strSafeSet(&b2->ExtraInstructions,"text=🛈;");b2->Flags|=LA_UI_FLAGS_PLAIN;{
+            laUiItem* ui=laShowItemFull(uil,cr,Base,"udf.path",LA_WIDGET_STRING_PLAIN, 0 ,0,0);ui->Expand=1;strSafeSet(&ui->ExtraInstructions,"text=Change");
+            laShowItem(uil,cr,&ui->PP,"get_file_path");
+        }laElse(uil,b2);{
+            laShowItemFull(uil,cr,Base,"basename", LA_WIDGET_STRING_PLAIN, 0 ,0,0)->Expand=1;
+        }laEndCondition(uil,b2);
+        laEndRow(uil, b);
+    }laElse(uil,b1);{
+        laShowItemFull(uil,cr,0,"LA_managed_save_new_file",0,"feedback=NONE;",0,0);
+    }laEndCondition(uil,b1);
+}
+void laui_ManagedPropInstance(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    if(!Base ||! Base->EndInstance ||Base->LastPs->p->PropertyType!=LA_PROP_SUB) return;
+    laColumn *c=laFirstColumn(uil);
+    laSplitColumn(uil,c,0.3); laColumn *cl=laLeftColumn(c, 1); laColumn *cr=laRightColumn(c,0);
+    laSplitColumn(uil,cr,0.6); laColumn *crl=laLeftColumn(cr, 30); laColumn *crr=laRightColumn(cr,0);
+
+    laPropContainer* pc=la_EnsureSubTarget(Base->LastPs->p, Base->EndInstance);
+    
+    if(pc->OtherAlloc || Base->LastPs->p->UDFIsSingle){
+        //laShowLabel(uil,cr,"(Item not allocated by memAcquire)",0,0)->Expand=1;
+    }else{
+        if(pc->Hyper==2){
+            laShowItem(uil,cl,Base,"__modified"); laSplitColumn(uil,crl,0.4); laColumn *crll=laLeftColumn(crl, 0); laColumn *crlr=laRightColumn(crl,10);
+            laUiItem* idui=laShowItem(uil,crll,Base,"identifier");idui->Flags|=LA_UI_FLAGS_PLAIN;idui->Expand=1;
+            laShowItem(uil,crlr,Base,"__uid")->Flags|=LA_UI_FLAGS_NO_DECAL;
+            if(pc->UDFPropagate){
+                laColumn *crrl,*crrr,*udfc,*optionc; laSplitColumn(uil,crr,0.7); crrl=laLeftColumn(crr,0); crrr=laRightColumn(crr,1);
+                laSplitColumn(uil,crrl,0.3); udfc=laLeftColumn(crrl,0); optionc=laRightColumn(crrl,8);
+                laUiItem* uc=laOnConditionToggle(uil,crrr,0,0,0,0,0);{ strSafeSet(&uc->ExtraInstructions,"text=⮯;");
+                    laShowItem(uil,udfc,Base,"__file");
+                    laUiItem* sr=laBeginRow(uil,optionc,1,0);
+                    laShowItemFull(uil,optionc,Base,"__udf_propagate",0,"force=true;text=Force;",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+                    laShowItemFull(uil,optionc,Base,"__udf_propagate",0,0,0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
+                    laEndRow(uil,sr);
+                }laElse(uil,uc);{
+                    laShowItem(uil,crrl,Base,"__file");
+                }laEndCondition(uil,uc);
+            }else{
+                laShowItem(uil,crr,Base,"__file");
+            }
+        }else{
+            laShowItem(uil,crl,Base,"identifier")->Flags|=LA_UI_FLAGS_PLAIN;
+        }
+    }
+    for(laProp*p=pc->Props.pFirst;p;p=p->Item.pNext){
+        if(p->PropertyType!=LA_PROP_SUB || p->UDFIsRefer) continue;
+        la_EnsureSubTarget(p,0); 
+        if(p->SubProp &&p->SubProp->Hyper!=2 &&(!p->UDFIsSingle)) continue;
+        if(p->UDFNoCreate) continue;
+        char buf[128]; sprintf(buf,"🞄 %s",p->Identifier);
+        laUiItem* b=laOnConditionToggle(uil,c,0,0,0,0,0);{ strSafePrint(&b->ExtraInstructions,"text=🞄 %s;",p->Identifier);
+            b->Flags|=LA_UI_FLAGS_NO_DECAL|LA_TEXT_ALIGN_LEFT; b->State=LA_BT_ACTIVE;
+            laShowItemFull(uil,cr,Base,p->Identifier,0, 0,laui_ManagedPropInstance,0)->Flags|=LA_UI_FLAGS_NO_DECAL|LA_UI_COLLECTION_NO_HIGHLIGHT;
+        }laEndCondition(uil,b);
+    }
+}
+void laui_ManagedProp(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c=laFirstColumn(uil);
+    laPropPack PP={0}; if(!Base ||! Base->EndInstance) return;
+
+    laManagedSaveProp* msp=Base->EndInstance;
+
+    laShowLabel(uil,c,msp->Path->Ptr,0,0);
+    laShowItemFull(uil,c,0,msp->Path->Ptr,0, 0,laui_ManagedPropInstance,0)->Flags|=LA_UI_FLAGS_NO_DECAL|LA_UI_COLLECTION_NO_HIGHLIGHT;
+}
+void laui_ManagedSavePanel(laUiList *uil, laPropPack *Base, laPropPack *Operator, laColumn *ExtraColumns, int context){
+    laManagedSaveExtra*mse=Operator->EndInstance;
+    laColumn *c=laFirstColumn(uil);
+
+    if(mse->OnExit){
+        laShowLabel(uil,c,"You still have unsaved/unassigned datablocks:",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_TEXT_LINE_WRAP;
+        laShowSeparator(uil,c);
+    }
+
+    laUiItem* r=laBeginRow(uil,c,0,0);
+    laShowLabel(uil,c,"Viewing",0,0);
+    laShowItem(uil,c,Operator,"show_page")->Flags|=LA_UI_FLAGS_EXPAND;
+    laEndRow(uil,r);
+    laUiItem* g=laMakeEmptyGroup(uil,c,"List",0);{ g->State=LA_UI_ACTIVE;
+        laUiList* gu=g->Page; gu->HeightCoeff=mse->OnExit?-4:-3; laColumn* gc=laFirstColumn(gu);
+        laUiItem* b=laOnConditionThat(gu,gc,laEqual(laPropExpression(Operator, "show_page"),laIntExpression(0)));{
+            laShowItemFull(gu,gc,0,"la.managed_props",0, 0,laui_ManagedProp,0)->Flags|=LA_UI_FLAGS_NO_DECAL|LA_UI_COLLECTION_NO_HIGHLIGHT;
+        }laElse(gu,b);{
+            laShowItemFull(gu,gc,0,"la.managed_udfs",0,0,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+        }laEndCondition(gu,b);     
+    }
+    
+    if(mse->OnExit){
+        laShowLabel(uil,c,"If you exit the program now, you will lose those changes.",0,0)->Flags|=LA_TEXT_ALIGN_CENTER|LA_TEXT_LINE_WRAP;
+    }
+
+    r=laBeginRow(uil,c,0,0);
+    if(mse->OnExit){
+        laShowItemFull(uil,c,0,"LA_cancel",0,"text=Discard And Quit;feedback=DISCARD_AND_QUIT",0,0);
+    }
+    laShowSeparator(uil,c)->Expand=1;
+    laShowItemFull(uil,c,0,"LA_managed_save",0,"quiet=true;ignore_unassigned=true;text=Save All Modified;feedback=SAVE_MODIFIED",0,0);
+    laEndRow(uil,r);
+}
+
+void laui_ResourceFolderItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c;
+
+    c = laFirstColumn(uil);
+    laUiItem* b=laBeginRow(uil,c,0,0);
+    laShowItem(uil, c, Base, "remove")->Flags|=LA_UI_FLAGS_ICON;
+    laUiItem* ui=laShowItem(uil, c, Base, "path");
+    ui->Expand=1;
+    laShowItem(uil,c,&ui->PP,"get_folder_path")->Flags|=LA_UI_FLAGS_ICON;
+    laEndRow(uil,b);
+}
+
+void laui_LogItem(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laShowItem(uil, ExtraColumns, Base, "content")->Flags|=LA_TEXT_LINE_WRAP|LA_TEXT_USE_NEWLINE|LA_TEXT_MONO;
+}
+
+
+void laui_UserPreference(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn* c = laFirstColumn(uil);
+    laUiList *muil;
+    laColumn *mc, *mcl, *mcr, *mcll, *mclr;
+    laUiItem *b, *bracket;
+
+    //_LA_PANEL_USER_PREFERENCE = p;
+    //la_UDFAppendSharedTypePointer("_LA_PANEL_USER_PREFERENCE", _LA_PANEL_USER_PREFERENCE);
+    //p->Show = 0;
+    //p->FastUpdate = 1;
+
+    bracket = laMakeTab(uil, c, 0);{
+        muil = laAddTabPage(bracket, "Display");{
+            //muil->HeightCoeff = -1;
+            mc = laFirstColumn(muil);
+            laSplitColumn(muil, mc, 0.5);
+            mcl = laLeftColumn(mc, 0);
+            mcr = laRightColumn(mc, 0);
+
+            laShowLabel(muil, mc, "Interface:", 0, 0);
+            laShowLabel(muil, mcl, "Row Height:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.interface_size");
+            laShowLabel(muil, mcl, "Font Size:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.font_size");
+            laShowLabel(muil, mcl, "Margin Size:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.margin_size");
+            laShowLabel(muil, mcl, "Panel Multisample:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.panel_multisample")->Flags|=LA_UI_FLAGS_EXPAND;
+            laShowItem(muil, mc, 0, "la.user_preferences.top_framerate");
+
+            laShowSeparator(muil, mc);
+
+            laShowLabel(muil, mc, "Nodes:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.wire_color_slices");
+            laShowItem(muil, mcr, 0, "la.user_preferences.wire_thickness");
+            laShowItem(muil, mcr, 0, "la.user_preferences.wire_saggyness");
+
+            laShowSeparator(muil, mc);
+
+            laShowLabel(muil, mc, "Floating Panel:", 0, 0);
+            laShowItem(muil, mcl, 0, "la.user_preferences.floating_alpha");
+            laShowItem(muil, mcr, 0, "la.user_preferences.solid_shadow_length");
+
+            laShowSeparator(muil, mc);
+
+            laShowLabel(muil, mc, "Translation:", 0, 0);
+            laShowLabel(muil, mcl, "Enable Translation:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.enable_translation");
+            b = laOnConditionThat(muil, mcl, laPropExpression(0, "la.user_preferences.enable_translation"));{
+            laShowLabel(muil, mcl, "Language:", 0, 0);
+                laShowItemFull(muil, mcr, 0, "la.user_preferences.languages", LA_WIDGET_COLLECTION_SELECTOR, 0, 0, 0);
+                laShowItem(muil, mcl, 0, "LA_translation_dump");
+            }
+            laEndCondition(muil, b);
+        }
+        
+        muil = laAddTabPage(bracket, "Input");{
+            //muil->HeightCoeff = -1;
+            mc = laFirstColumn(muil);
+            laSplitColumn(muil, mc, 0.5);
+            mcl = laLeftColumn(mc, 0);
+            mcr = laRightColumn(mc, 0);
+
+            laShowLabel(muil, mc, "User Interactions:", 0, 0);
+            laShowItem(muil, mc, 0, "la.user_preferences.scroll_speed");
+            laShowItem(muil, mcl, 0, "la.user_preferences.animation_speed");
+            laShowItem(muil, mcr, 0, "la.user_preferences.panel_animation_speed");
+            laShowItem(muil, mc, 0, "la.user_preferences.valuator_threshold");
+            laShowItem(muil, mc, 0, "la.user_preferences.zoom_speed_2d");
+            laShowItem(muil, mcl, 0, "la.user_preferences.tooltip_close_distance");
+            laShowItem(muil, mcr, 0, "la.user_preferences.idle_time");
+        }
+
+        muil = laAddTabPage(bracket, "Resource");{
+            //muil->HeightCoeff = -1;
+            mc = laFirstColumn(muil);
+
+            laSplitColumn(muil, mc, 0.5);
+            mcl = laLeftColumn(mc, 0);
+            mcr = laRightColumn(mc, 0);
+            laShowLabel(muil, mcl, "UDF Manager Default View:", 0, 0);
+            laShowItem(muil, mcr, 0, "la.user_preferences.manager_default_view")->Flags|=LA_UI_FLAGS_EXPAND;
+
+            laShowSeparator(muil,mc);
+
+            b=laBeginRow(muil,mc,0,0);
+            laShowLabel(muil, mc, "Resource Folders", 0, 0)->Expand=1;
+            laShowItem(muil, mc, 0, "LA_add_resource_folder");
+            laEndRow(muil,b);
+            laShowItem(muil, mc, 0, "la.user_preferences.resource_folders");
+        }
+
+        muil = laAddTabPage(bracket, "Theme");{
+            //muil->HeightCoeff = -1;
+            mc = laFirstColumn(muil);
+            laShowLabel(muil, mc, "Active Theme", 0, 0);
+            laShowItemFull(muil, mc, 0, "la.themes", LA_WIDGET_COLLECTION_SELECTOR, 0,laui_ThemeListItem,0);
+            laShowItemFull(muil, mc, 0, "la.themes", LA_WIDGET_COLLECTION_SINGLE, 0 ,0,0);
+        }
+    }
+}
+void laui_About(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn *c, *cl, *cr, *tc, *gc, *gcl, *gcr, *tcl, *tcr;
+    laUiItem *bracket, *t, *g;
+    laPanel *p;
+    laUiList *u, *gu;
+    laPropContainer *pc;
+    int h;
+    laOperatorType *at;
+    laUiList *first;
+    char buf[2048]={0};
+
+    c = laFirstColumn(uil);
+
+    laShowLabel(uil, c, "LaGUI", 0, 0);
+    laShowLabel(uil, c, "2022", 0, 0);
+    laShowLabel(uil, c, "(C)Yiming Wu", 0, 0);
+
+    t = laMakeTab(uil, c, 0);{
+        first = u = laAddTabPage(t, "Version");
+        u->HeightCoeff=-1;
+        tc = laFirstColumn(u);
+
+        g = laMakeGroup(u, tc, "User Interface", 0);
+        gu = g->Page;{
+            gc = laFirstColumn(gu);
+
+            //laShowSymbol(gu, gc, 0, 0);
+            laShowSymbol(gu, gc, 0, 0);
+            laShowLabel(gu, gc, "A graphical user interface application toolkit", 0, 0)->Flags|=LA_TEXT_LINE_WRAP;;
+            laShowLabel(gu, gc, "(C)YimingWu", 0, 0);
+
+            sprintf(buf, "🛈 LA.%d.%d.%d", LA_VERSION_MAIN, LA_VERSION_SUB, LA_VERSION_MINOR);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+            laShowLabel(gu, gc, "🗇" " Branch:master", 0, 0);
+            sprintf(buf, "📅 Date:[UTC+8] %s %s", __DATE__, __TIME__);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+            sprintf(buf, "🖹 UDF Capability %d.%d.%d", LA_UDF_CAPABILITY_MAIN, LA_UDF_CAPABILITY_SUB, LA_UDF_CAPABILITY_MINOR);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+        }
+        
+        g = laMakeGroup(u, tc, "Graphics Information", 0);
+        gu = g->Page;{
+            gc = laFirstColumn(gu);
+            laSplitColumn(gu, gc, 0.6);
+            gcl = laLeftColumn(gc, 0);
+            gcr = laRightColumn(gc, 0);
+            laShowSymbol(gu, gcl, 0, 0);
+
+            laShowLabel(gu, gc, "The interface uses OpenGL as the graphics backend", 0, 0)->Flags|=LA_TEXT_LINE_WRAP;
+
+            sprintf(buf, "🛈" " OpenGL Version: %s", T->GLVersionStr);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+            sprintf(buf, "🛈" " OpenGL Vendor: %s", T->GLVendorStr);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+            sprintf(buf, "🛈" " OpenGL Renderer: %s", T->GLRendererStr);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+            sprintf(buf, "🛈" " GLSL Version: %s", T->GLSLVersionStr);
+            laShowLabelDynamic(gu, gc, buf, 0, 0);
+        }
+
+        g = laMakeGroup(u, tc, "Build Tool", 0);
+        gu = g->Page;{
+            gc = laFirstColumn(gu);
+            laShowSymbol(gu, gc, 0, 0);
+            laShowLabel(gu, gc, "This Program Is Built With GCC Tool Chain", 0, 0)->Flags|=LA_TEXT_LINE_WRAP;
+        }
+
+        u = laAddTabPage(t, "Props");{
+            c = laFirstColumn(u);
+            laSplitColumn(u, c, 0.2);
+            gcl = laLeftColumn(c, 1);
+            gcr = laRightColumn(c, 0);
+            for (pc = MAIN.PropContainers.pFirst; pc; pc = pc->Item.pNext){
+                buf[0] = L' ';buf[1]= L'\0';
+                if(pc->IconID){
+                    sprintf(buf, "%lc", pc->IconID);
+                }
+                laShowLabelDynamic(u, gcl, buf, 0, LA_WIDGET_STRING_PLAIN);
+                laShowLabelDynamic(u, gcr, pc->Identifier, 0, LA_WIDGET_STRING_PLAIN);
+            }
+        }
+
+        u = laAddTabPage(t, "Functions");{
+            c = laFirstColumn(u);
+            laSplitColumn(u, c, 0.2);
+            gcl = laLeftColumn(c, 1);
+            gcr = laRightColumn(c, 0);
+            for (h = 0; h < 256; h++){
+                for (at = MAIN.OperatorTypeHash.Entries[h].pFirst; at; at = at->Item.pNext){
+                    buf[0] = L' ';buf[1]= L'\0';
+                    if(at->IconID){
+                        sprintf(buf, "%lc", at->IconID);
+                    }
+                    laShowLabelDynamic(u, gcl, buf, 0, LA_WIDGET_STRING_PLAIN);
+                    laShowLabelDynamic(u, gcr, at->Identifier, 0, LA_WIDGET_STRING_PLAIN);
+                }
+            }
+        }
+
+        u = laAddTabPage(t, "Contact");
+        tc = laFirstColumn(u);
+        laSplitColumn(u, tc, 0.8);
+        tcl = laLeftColumn(tc, 60);
+        tcr = laRightColumn(tc, 00);
+
+        strSafeSet(&laShowSymbol(u, tc, 0, 0)->ExtraInstructions, "mode=invert;preserve=5;");
+
+        laShowItemFull(u, tcl, 0, "LA_open_internet_link", 0, "link=http://www.wellobserve.com;", 0, 0);
+        laShowLabel(u, tcr, "Yiming's Website", 0, 0);
+        laShowSeparator(u, tc);
+
+        laShowLabel(u, tcr, "QQ 1094469528", 0, 0);
+        laShowSeparator(u, tc);
+
+        laShowItemFull(u, tcl, 0, "LA_open_internet_link", 0, "link=http://weibo.com/1919404360;", 0, 0);
+        laShowLabel(u, tcr, "Weibo", 0, 0);
+
+        laShowItemFull(u, tcl, 0, "LA_open_internet_link", 0, "link=https://www.artstation.com/artist/nicksbest;", 0, 0);
+        laShowLabel(u, tcr, "Artstation", 0, 0);
+
+        laShowItemFull(u, tcl, 0, "LA_open_internet_link", 0, "link=mailto:1094469528@qq.com;icon=🖅", 0, 0);
+        laShowLabel(u, tcr, "QQ Mail", 0, 0);
+
+        laShowLabel(u, tcr, "Outlook Mail", 0, 0);
+        laShowItemFull(u, tcl, 0, "LA_open_internet_link", 0, "link=mailto:xp8110@outlook.com;icon=🖅", 0, 0);
+
+        t->Page = first;
+    }
+}
+void laui_terminal(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
+    laColumn* c=laFirstColumn(uil);
+    laUiItem* g=laMakeGroup(uil,c,"123",0);{ g->State=LA_UI_ACTIVE; g->Flags|=LA_UI_FLAGS_PREFER_BOTTOM;
+        laUiList* gu=g->Page; laColumn* gc=laFirstColumn(gu); gu->HeightCoeff=-1;
+        laShowItem(gu,gc,0,"la.logs")->Flags|=LA_UI_FLAGS_NO_DECAL;
+    }
+}
+void laui_IdleDataManager(laUiList *uil, laPropPack *Base, laPropPack *Extra, laColumn *ExtraColumns, int context){
+    laColumn *c=laFirstColumn(uil);
+
+    laUiItem* r=laBeginRow(uil,c,0,0);
+    laShowLabel(uil,c,"Viewing",0,0);
+    laShowItem(uil,c,Extra,"show_page")->Flags|=LA_UI_FLAGS_EXPAND;
+    laEndRow(uil,r);
+    laUiItem* g=laMakeEmptyGroup(uil,c,"List",0);{ g->State=LA_UI_ACTIVE;
+        laUiList* gu=g->Page; gu->HeightCoeff=-3; laColumn* gc=laFirstColumn(gu);
+        laUiItem* b=laOnConditionThat(gu,gc,laEqual(laPropExpression(Extra, "show_page"),laIntExpression(0)));{
+            laShowItemFull(gu,gc,0,"la.managed_props",0, 0,laui_ManagedProp,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+        }laElse(gu,b);{
+            laShowItemFull(gu,gc,0,"la.managed_udfs",0,0,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+        }laEndCondition(gu,b);     
+    }
+    
+    r=laBeginRow(uil,c,0,0);
+    laShowSeparator(uil,c)->Expand=1;
+    laShowItemFull(uil,c,0,"LA_managed_save",0,"quiet=true;ignore_unassigned=true;text=Save All Modified",0,0);
+    laEndRow(uil,r);
+}
+void lauidetached_IdleDataManager(laPanel* p){
+    la_MakeDetachedProp(p, "la.user_preferences.manager_default_view", "show_page");
+}
+void laui_TextureInspector(laUiList *uil, laPropPack *Base, laPropPack *Extra, laColumn *ExtraColumns, int context){
+    laColumn *c=laFirstColumn(uil),*cl,*cr;
+    laSplitColumn(0, c, 0.5);
+    cl = laLeftColumn(c, 0);
+    cr = laRightColumn(c, 0);
+
+    laShowLabel(uil,cl,"Viewing Texture:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT;
+    laShowItemFull(uil,cr,Extra,"textures",LA_WIDGET_COLLECTION_SELECTOR,0,0,0);
+    laUiItem* u2=laShowCanvas(uil,c,Extra,"textures",0,-1);
+    laDefault2DViewOverlayRight(u2);
+}
+void lauidetached_TextureInspector(laPanel* p){
+    la_MakeDetachedProp(p, "tns.texture_list", "textures");
+}
+void laui_GameController(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil),*cl, *cr;
+    laSplitColumn(uil,c,0.5); cl=laLeftColumn(c,0); cr=laRightColumn(c,0);
+    laShowLabel(uil,cl,"Controller:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT;
+    laShowItemFull(uil,cr,Extra,"controllers",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+    laShowItemFull(uil,c,Extra,"controllers",LA_WIDGET_COLLECTION_SINGLE,0,0,0);
+}
+void lauidetached_GameController(laPanel* p){
+    la_MakeDetachedProp(p, "la.controllers", "controllers");
+}
+
+
+void la_RegisterBuiltinTemplates(){
+    //laRegisterUiTemplate("LAUI_default_subwindow_menubar", "Menu", laui_DefaultSubWindowMenuBarActual, 0);
+    //laRegisterUiTemplate("LAUI_default_menubar", "Menu", laui_DefaultMenuBarActual, 0);
+    laRegisterUiTemplate("LAUI_user_preferences", "User Preferences", laui_UserPreference, 0, 0);
+    laRegisterUiTemplate("LAUI_about", "About", laui_About, 0, 0);
+    laRegisterUiTemplate("LAUI_texture_inspector", "Texture Inspector", laui_TextureInspector, lauidetached_TextureInspector, 0);
+    laRegisterUiTemplate("LAUI_data_manager", "Data Manager", laui_IdleDataManager, lauidetached_IdleDataManager, 0);
+    laRegisterUiTemplate("LAUI_terminal", "Terminal", laui_terminal, 0, 0);
+    laRegisterUiTemplate("LAUI_controllers", "Controllers", laui_GameController, lauidetached_GameController, 0);
+}

+ 2741 - 0
source/lagui/resources/la_widgets.c

@@ -0,0 +1,2741 @@
+#include "../la_5.h"
+
+extern LA MAIN;
+
+laWidget _LA_WIDGET_FIXED_GROUP={0};
+laWidget _LA_WIDGET_TAB={0};
+laWidget _LA_WIDGET_COLLECTION={0};
+laWidget _LA_WIDGET_COLLECTION_ITEM={0};
+laWidget _LA_WIDGET_COLLECTION_SELECTOR={0};
+laWidget _LA_WIDGET_COLLECTION_SINGLE={0};
+laWidget _LA_WIDGET_CONDITION_TOGGLE={0};
+laWidget _LA_WIDGET_COLUMN_ADJUSTER={0,LA_UI_FLAGS_NO_HEIGHT};
+laWidget _LA_WIDGET_COLUMN_VIEWER={0};
+laWidget _LA_WIDGET_BUTTON={0};
+laWidget _LA_WIDGET_BUTTON_NO_CONFIRM={0};
+laWidget _LA_WIDGET_LABEL={0};
+laWidget _LA_WIDGET_INT={0};
+laWidget _LA_WIDGET_INT_PLAIN={0, LA_UI_FLAGS_PLAIN};
+laWidget _LA_WIDGET_INT_PLAIN_ICON={0, LA_UI_FLAGS_INT_ICON};
+laWidget _LA_WIDGET_INT_METER={0,LA_TEXT_ALIGN_CENTER};
+laWidget _LA_WIDGET_INT_METER_2D={0,LA_TEXT_ALIGN_CENTER};
+laWidget _LA_WIDGET_FLOAT={0};
+laWidget _LA_WIDGET_FLOAT_PLAIN={0, LA_UI_FLAGS_PLAIN};
+laWidget _LA_WIDGET_FLOAT_COLOR={0};
+laWidget _LA_WIDGET_FLOAT_HCY={0};
+laWidget _LA_WIDGET_ENUM_SELECTOR={0};
+laWidget _LA_WIDGET_ENUM_SELECTOR_ICON={0, LA_UI_FLAGS_ICON};
+laWidget _LA_WIDGET_ENUM_CYCLE={0, LA_UI_FLAGS_CYCLE};
+laWidget _LA_WIDGET_ENUM_CYCLE_ICON={0, LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_ICON};
+laWidget _LA_WIDGET_ENUM_ICON_PLAIN={0, LA_UI_FLAGS_PLAIN|LA_UI_FLAGS_ICON};
+laWidget _LA_WIDGET_ENUM_HIGHLIGHT={0, LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_CYCLE|LA_TEXT_ALIGN_CENTER};
+laWidget _LA_WIDGET_STRING={0};
+laWidget _LA_WIDGET_STRING_PLAIN={0, LA_UI_FLAGS_PLAIN};
+laWidget _LA_WIDGET_STRING_MONO_PLAIN={0, LA_TEXT_MONO|LA_UI_FLAGS_PLAIN};
+laWidget _LA_WIDGET_STRING_MULTI={0, LA_TEXT_MONO};
+laWidget _LA_WIDGET_MENU_ROOT={0};
+laWidget _LA_WIDGET_ALIGN={0};
+laWidget _LA_WIDGET_3D_VIEW={0};
+laWidget _LA_WIDGET_2D_VIEW={0};
+laWidget _LA_WIDGET_SYMBOL={0};
+laWidget _LA_WIDGET_NODE_SOCKET={0};
+laWidget _LA_WIDGET_HEIGHT_ADJUSTER={0};
+laWidget _LA_WIDGET_RAW={0};
+
+laWidget *LA_WIDGET_FIXED_GROUP=&_LA_WIDGET_FIXED_GROUP;
+laWidget *LA_WIDGET_TAB=&_LA_WIDGET_TAB;
+laWidget *LA_WIDGET_COLLECTION=&_LA_WIDGET_COLLECTION;
+laWidget *LA_WIDGET_COLLECTION_ITEM=&_LA_WIDGET_COLLECTION_ITEM;
+laWidget *LA_WIDGET_COLLECTION_SELECTOR=&_LA_WIDGET_COLLECTION_SELECTOR;
+laWidget *LA_WIDGET_COLLECTION_SINGLE=&_LA_WIDGET_COLLECTION_SINGLE;
+laWidget *LA_WIDGET_CONDITION_TOGGLE=&_LA_WIDGET_CONDITION_TOGGLE;
+laWidget *LA_WIDGET_COLUMN_ADJUSTER=&_LA_WIDGET_COLUMN_ADJUSTER;
+laWidget *LA_WIDGET_COLUMN_VIEWER=&_LA_WIDGET_COLUMN_VIEWER;
+laWidget *LA_WIDGET_BUTTON=&_LA_WIDGET_BUTTON;
+laWidget *LA_WIDGET_BUTTON_NO_CONFIRM=&_LA_WIDGET_BUTTON_NO_CONFIRM;
+laWidget *LA_WIDGET_LABEL=&_LA_WIDGET_LABEL;
+laWidget *LA_WIDGET_INT=&_LA_WIDGET_INT;
+laWidget *LA_WIDGET_INT_PLAIN=&_LA_WIDGET_INT_PLAIN;
+laWidget *LA_WIDGET_INT_PLAIN_ICON=&_LA_WIDGET_INT_PLAIN_ICON;
+laWidget *LA_WIDGET_INT_METER=&_LA_WIDGET_INT_METER;
+laWidget *LA_WIDGET_INT_METER_2D=&_LA_WIDGET_INT_METER_2D;
+laWidget *LA_WIDGET_FLOAT=&_LA_WIDGET_FLOAT;
+laWidget *LA_WIDGET_FLOAT_PLAIN=&_LA_WIDGET_FLOAT_PLAIN;
+laWidget *LA_WIDGET_FLOAT_COLOR=&_LA_WIDGET_FLOAT_COLOR;
+laWidget *LA_WIDGET_FLOAT_HCY=&_LA_WIDGET_FLOAT_HCY;
+laWidget *LA_WIDGET_ENUM_SELECTOR=&_LA_WIDGET_ENUM_SELECTOR;
+laWidget *LA_WIDGET_ENUM_SELECTOR_ICON=&_LA_WIDGET_ENUM_SELECTOR_ICON;
+laWidget *LA_WIDGET_ENUM_CYCLE=&_LA_WIDGET_ENUM_CYCLE;
+laWidget *LA_WIDGET_ENUM_CYCLE_ICON=&_LA_WIDGET_ENUM_CYCLE_ICON;
+laWidget *LA_WIDGET_ENUM_ICON_PLAIN=&_LA_WIDGET_ENUM_ICON_PLAIN;
+laWidget *LA_WIDGET_ENUM_HIGHLIGHT=&_LA_WIDGET_ENUM_HIGHLIGHT;
+laWidget *LA_WIDGET_STRING=&_LA_WIDGET_STRING;
+laWidget *LA_WIDGET_STRING_PLAIN=&_LA_WIDGET_STRING_PLAIN;
+laWidget *LA_WIDGET_STRING_MULTI=&_LA_WIDGET_STRING_MULTI;
+laWidget *LA_WIDGET_STRING_MONO_PLAIN=&_LA_WIDGET_STRING_MONO_PLAIN;
+laWidget *LA_WIDGET_MENU_ROOT=&_LA_WIDGET_MENU_ROOT;
+laWidget *LA_WIDGET_ALIGN=&_LA_WIDGET_ALIGN;
+laWidget *LA_WIDGET_3D_VIEW=&_LA_WIDGET_3D_VIEW;
+laWidget *LA_WIDGET_2D_VIEW=&_LA_WIDGET_2D_VIEW;
+laWidget *LA_WIDGET_SYMBOL=&_LA_WIDGET_SYMBOL;
+laWidget *LA_WIDGET_NODE_SOCKET=&_LA_WIDGET_NODE_SOCKET;
+laWidget *LA_WIDGET_HEIGHT_ADJUSTER=&_LA_WIDGET_HEIGHT_ADJUSTER;
+laWidget *LA_WIDGET_RAW=&_LA_WIDGET_RAW;
+
+//============================================== [Draw]
+
+int la_ArrayGetHeight(laUiItem *ui){
+    return laGetArrayLength(&ui->PP);
+}
+int la_ValueGetHeight(laUiItem*ui){
+    if(ui->Flags&LA_UI_FLAGS_TRANSPOSE){ return la_ArrayGetHeight(ui); }
+    return 1;
+}
+int la_IntMeterGetHeight(laUiItem*ui){
+    if(ui->Flags&LA_UI_FLAGS_TRANSPOSE){ return ui->Extra->HeightCoeff?ui->Extra->HeightCoeff:6; }
+    return laGetArrayLength(&ui->PP);
+}
+int la_IntMeter2DGetHeight(laUiItem*ui){
+    return ui->Extra->HeightCoeff?ui->Extra->HeightCoeff:(ui->Extra->HeightCoeff=(ui->TR-ui->TL)/LA_RH);
+}
+int la_CanvasGetHeight(laUiItem *ui){
+    return ui->Expand;
+}
+int la_EnumGetHeight(laUiItem *ui){
+    // norm      e1
+    // expand    e1 e2 e3
+    // expand vertical  (vertical)
+    // arr expand    e1 e2 e3
+    //               e1 e2 e3
+    // arr exp+vert  e1 e1
+    //               e2 e2
+    //               e3 e3
+    int IsVertical = ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+    int IsExpand = ui->Flags&LA_UI_FLAGS_EXPAND;
+    int IsCycle = ui->Flags&LA_UI_FLAGS_CYCLE;
+    int ArrLen = laGetArrayLength(&ui->PP);
+    if(ArrLen==1){ if(!IsExpand) IsVertical=0; }else{ IsExpand=1; }
+    int EnumLen = (IsExpand&&(!IsCycle)) ? laGetEnumEntryLen(&ui->PP) : 1;
+    if(ArrLen==1){
+        if(IsVertical&&IsExpand) return laGetEnumEntryLen(&ui->PP);
+        return 1;
+    }else{
+        if(IsVertical) return EnumLen;
+        else return ArrLen;
+    }
+}
+int la_ColorPickerGetHeight(laUiItem *ui){
+    return 7;
+}
+int la_SymbolGetHeight(laUiItem *ui){
+    //if (!ui->State)
+    //{
+    //    ui->State = (int)_ICON_SYMBOL_SIZE[ui->SymbolID - ICON_SYMBOL_START] * 1.4 + 1;
+    //}
+    return ui->State;
+}
+int la_GroupGetHeight(laUiItem *ui){
+    if (ui->State == LA_UI_ACTIVE) return 0;
+    return LA_RH;
+}
+int la_StringPropGetHeight(laUiItem *ui){
+    laBoxedTheme *bt = *ui->Type->Theme;
+    if(!(ui->Flags&LA_TEXT_LINE_WRAP)) return 1;
+    char _buf[LA_RAW_CSTR_MAX_LEN]={0}; char* buf=_buf;
+    laGetString(&ui->PP, _buf, &buf); int rows=0;
+    int strw=tnsStringGetDimension(buf, 0, 0, ui->TR-ui->TL, &rows, ui->Flags&LA_TEXT_MONO);
+    return rows;
+}
+int la_MultiStringHeight(laUiItem *ui){
+    laGeneralUiExtraData *e = ui->Extra;
+    return e->HeightCoeff;
+}
+int la_LabelHeight(laUiItem *ui){
+    int Wrap=ui->Flags&LA_TEXT_LINE_WRAP;
+    if(!Wrap) return 1;
+    int rows;
+    tnsStringGetDimension(ui->Display->Ptr, 0, 0, ui->TR-ui->TL, &rows, ui->Flags&LA_TEXT_MONO);
+    return rows;
+}
+
+int la_ValueGetMinWidth(laUiItem *ui){
+    return LA_RH*4;
+}
+int la_LabelGetMinWidth(laUiItem *ui){
+    laBoxedTheme *bt = *ui->Type->Theme;
+    int strw=tnsStringGetWidth(ui->Display->Ptr, 0, ui->Flags&LA_TEXT_MONO);
+    if(ui->Type==_LA_UI_MENU_ROOT && strw<LA_RH)strw=LA_RH;
+    return (strw + bt->LM + bt->RM);
+}
+int la_StringPropGetMinWidth(laUiItem *ui){
+    laBoxedTheme *bt = *ui->Type->Theme;
+    char _buf[LA_RAW_CSTR_MAX_LEN]={0}; int ExtraW=0; char* buf=_buf;
+    if(ui->Type == _LA_UI_STRING_MULTI){ExtraW=2*LA_RH+bt->LM;}
+    laGetString(&ui->PP, _buf, &buf); int rows=0;
+    int strw=tnsStringGetDimension(buf, 0, 0, 0, &rows, ui->Flags&LA_TEXT_MONO);
+    int Plain = ui->Flags&LA_UI_FLAGS_PLAIN;
+    if((!Plain)&&strw<LA_RH*4){strw=LA_RH*4;}
+    return (strw + bt->LM + bt->RM+ExtraW);
+}
+int la_EnumGetMinWidth(laUiItem *ui){
+    laBoxedTheme *bt = *ui->Type->Theme;
+    laEnumProp *ep = ui->PP.LastPs->p;
+    laEnumItem *i;
+    int W = 0; int tW;
+    int IsVertical = ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+    int IsExpand = ui->Flags&LA_UI_FLAGS_EXPAND;
+    int IsCycle = ui->Flags&LA_UI_FLAGS_CYCLE;
+    int IsIcon = ui->Flags&LA_UI_FLAGS_ICON;
+    int SharedWidth;
+    if(!IsIcon){
+        SharedWidth = bt->LM + bt->RM + ((IsCycle||IsExpand)?0:LA_RH); int HasIcon=0;
+        for (i = ep->Items.pFirst; i; i = i->Item.pNext){
+            tW = tnsStringGetWidth(i->Name, 0, ui->Flags&LA_TEXT_MONO) + SharedWidth;
+            if (i->IconID){ HasIcon=1; }
+            if (tW > W) W = tW;
+        }
+        if(HasIcon) W+=bt->LM+LA_RH;
+    }else{
+        W = LA_RH;
+    }
+    int ArrLen = laGetArrayLength(&ui->PP);
+    if(ArrLen==1){ if(!IsExpand) IsVertical=0; }else{ IsExpand=1; }
+    int EnumLen = (IsExpand&&(!IsCycle)) ? laGetEnumEntryLen(&ui->PP) : 1;
+    if(ArrLen==1){
+        if(!IsVertical) return W*EnumLen;
+        return W;
+    }else{
+        if(IsVertical) return ArrLen*W;
+        return EnumLen*W;
+    }
+    return W;
+}
+int la_ButtonGetMinWidth(laUiItem *ui){
+    laBoxedTheme *bt = *ui->Type->Theme;
+    uint32_t IconID;
+    char buf[LA_RAW_CSTR_MAX_LEN]={0};
+    char *label;
+    laOperatorProp *ap;
+    int IconOnly=ui->Flags&LA_UI_FLAGS_ICON;
+
+    if(IconOnly) return LA_RH;
+
+    if (ui->PP.LastPs && ui->PP.LastPs->p){
+        ap = ui->PP.LastPs->p;
+        label = ap->Base.Name;
+        IconID = ap->Base.IconID ? ap->Base.IconID : ap->OperatorType->IconID;
+        if (!ap->OperatorType) ap->OperatorType = laGetOperatorType(ap->OperatorID);
+    }else{
+        label = ui->AT->Name;
+        IconID = ui->AT->IconID;
+    }
+
+    if (ui->ExtraInstructions){
+        if (ui->AT && ui->AT->ParseArgs){
+            ui->AT->ParseArgs(ui->Instructions, &IconID, buf);
+            if (buf[0]) label = buf;
+        }else if (ui->PP.LastPs->p->PropertyType == LA_PROP_OPERATOR){
+            laOperatorProp *ap = ui->PP.LastPs->p;
+            if (ap->OperatorType && ap->OperatorType->ParseArgs){
+                ap->OperatorType->ParseArgs(ui->Instructions, &IconID, buf);
+                if (buf[0]) label = buf;
+            }
+        }
+    }
+
+    int strw=tnsStringGetWidth(label, 0, ui->Flags&LA_TEXT_MONO);
+    if(strw){ strw+=bt->RM+bt->LM; }
+
+    return ((IconID ? (LA_RH) : 0) + strw);
+}
+int la_ColumnViewerGetMinWidth(laUiItem *ui){
+    return 350;
+}
+int la_ColorPickerGetMinWidth(laUiItem *ui){
+    return LA_RH * 9;
+}
+int la_SocketGetMinWidth(laUiItem *ui){
+    return LA_RH;
+}
+
+void la_SingleLineStringDrawSelection(laUiItem *ui, int Begin, int U, laBoxedTheme *bt, uint32_t *str, laStringEdit *se);
+
+void la_CollectionSelectorDraw(laUiItem *ui, int h){
+    char temp[128] = {0};
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    real Color[16] = {0};
+    tnsVector4d Transp = {0};
+    int CrossDraw = 0;
+
+    if (!ui->State) ui->State = LA_UI_NORMAL;
+
+    tnsUseNoTexture();
+    tnsColor4dv(laThemeColor(bt,ui->State));
+    tnsVertex2d(ui->L, ui->U);
+    tnsVertex2d(ui->R, ui->U);
+    tnsVertex2d(ui->R, ui->B);
+    tnsVertex2d(ui->L, ui->B);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    CrossDraw = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance) ? 1 : 0;
+
+    if (CrossDraw){
+        tnsVectorCopy4d(laThemeColor(bt,LA_BT_BORDER), Transp);
+        Transp[3] = 0;
+
+        tnsMakeLinerGradient4dv(Color, 2, Transp, laThemeColor(bt,LA_BT_BORDER));
+        tnsMakeLinerGradient4dv(&Color[8], 2, Transp, laThemeColor(bt,LA_BT_BORDER));
+        //tnsMakeLinerGradient4dv(&Color[8], 2, laThemeColor(bt, LA_BT_BORDER), Transp);
+        tnsVertex2d(ui->R - LA_RH, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R - LA_RH, ui->B);
+        tnsVertex2d(ui->R, ui->B);
+        tnsColorArray4d(Color, 4);
+
+        tnsPackAs(GL_TRIANGLE_STRIP);
+    }
+
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertex2d(ui->L, ui->U);
+    tnsVertex2d(ui->R, ui->U);
+    tnsVertex2d(ui->R, ui->B);
+    tnsVertex2d(ui->L, ui->B);
+    tnsPackAs(GL_LINE_LOOP);
+
+    if (CrossDraw){
+        tnsDrawStringAuto("🧹", laThemeColor(bt,ui->State|LA_BT_TEXT), ui->R - LA_RH, ui->R, ui->U, 0);
+    }
+}
+void la_EmptyDraw(laUiItem *ui, int h){
+    char temp[128] = {0};
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    if (!ui->State) ui->State = LA_UI_NORMAL;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+}
+void la_GroupDraw(laUiItem *ui, int h){
+    char temp[128] = {0};
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    if (ui->State != LA_UI_ACTIVE){
+        tnsDrawStringAuto(ui->Page ? transLate(ui->Page->TabName->Ptr) : transLate("No Page"),
+            laThemeColor(bt,ui->State|LA_BT_TEXT), ui->L+bt->LM, ui->R+bt->RM, ui->U, LA_TEXT_ALIGN_CENTER);
+    }
+}
+void la_TabDraw(laUiItem *ui, int h){
+    char temp[128] = {0};
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laUiList *uil;
+    int count = 0;
+    int w; // = (ui->R - ui->L) / count;
+    int page = 0;
+    int l = ui->L;
+
+    for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){
+        count++;
+    }
+
+    w = (ui->R - ui->L) / (count == 0 ? 1 : count);
+
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U + h);
+        tnsVertex2d(ui->L, ui->B);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->R, ui->U + h);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){
+        l = page * w;
+        if (uil != ui->Page){
+            tnsUseNoTexture();
+            tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE));
+            tnsVertex2d(ui->L + l, ui->U);
+            tnsVertex2d(ui->L + l + w, ui->U);
+            tnsVertex2d(ui->L + l + w, ui->U + h);
+            tnsVertex2d(ui->L + l, ui->U + h);
+            tnsPackAs(GL_TRIANGLE_FAN);
+            tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+            tnsVertex2d(ui->L + l, ui->U + h);
+            tnsVertex2d(ui->L + l, ui->U);
+            tnsVertex2d(ui->L + l + w, ui->U);
+            tnsVertex2d(ui->L + l + w, ui->U + h);
+            tnsPackAs(GL_LINE_STRIP);
+            tnsDrawStringAuto(transLate(uil->TabName->Ptr), laThemeColor(bt,LA_BT_TEXT), ui->L+l+bt->LM, ui->L+l+w-bt->RM, ui->U, LA_TEXT_ALIGN_CENTER);
+        }else{
+            tnsUseNoTexture();
+            tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+            tnsVertex2d(ui->L + l, ui->U);
+            tnsVertex2d(ui->L + l + w, ui->U);
+            tnsVertex2d(ui->L + l + w, ui->U + h);
+            tnsVertex2d(ui->L + l, ui->U + h);
+            tnsPackAs(GL_TRIANGLE_FAN);
+            tnsDrawStringAuto(transLate(uil->TabName->Ptr), laThemeColor(bt,LA_BT_TEXT_ACTIVE), ui->L+l+bt->LM, ui->L+l+w-bt->RM, ui->U, LA_TEXT_ALIGN_CENTER);
+        }
+
+        page++;
+    }
+    tnsFlush();
+}
+void la_SymbolDraw(laUiItem *ui, int h){
+    return;
+    //char temp[128] = {0};
+    //laBoxedTheme *bt = (*ui->Type->Theme);
+    //tnsFontSingleCharacter *fsc = tfntFetchVectorGraphTextureIDW(ui->SymbolID);
+    //int VOffset = (ui->B - ui->U - (fsc->height)) / 2;
+    //int HOffset = (ui->R - ui->L - (fsc->width)) / 2;
+//
+    //if (strArgumentMatch(ui->Instructions, "mode", "invert"))
+    //{
+    //    tnsUseNoTexture();
+    //    //tnsColor4dv(laThemeColor(bt, ui->State));
+    //    //tnsVertex2d(ui->L, ui->U);
+    //    //tnsVertex2d(ui->R, ui->U);
+    //    //tnsVertex2d(ui->R, ui->B);
+    //    //tnsVertex2d(ui->L, ui->B);
+    //    //tnsPackAs(GL_TRIANGLE_FAN);
+//
+    //    tnsUseNoTexture();
+    //    tnsColor4dv(LA_THEME_GET(bt, LA_UI_NORMAL)->BorderColor->RGBA);
+    //    tnsVertex2d(ui->L, ui->U);
+    //    tnsVertex2d(ui->R, ui->U);
+    //    tnsVertex2d(ui->R, ui->B);
+    //    tnsVertex2d(ui->L, ui->B);
+    //    tnsPackAs(GL_TRIANGLE_FAN);
+//
+    //    //    tnsDrawVectorGraphPackage(ui->SymbolID, LA_THEME_GET(bt, LA_THEME_INTERPOLATING), ui->L + HOffset, ui->R, ui->U + VOffset, ui->B, 0, 0);
+    //}
+    //else
+    //{
+    //    //if (!ui->State) ui->State = LA_UI_NORMAL;
+//
+    //    /*tnsUseNoTexture();
+    //    tnsColor4dv(laThemeColor(bt, ui->State));
+    //    tnsVertex2d(ui->L, ui->U);
+    //    tnsVertex2d(ui->R, ui->U);
+    //    tnsVertex2d(ui->R, ui->B);
+    //    tnsVertex2d(ui->L, ui->B);
+    //    tnsPackAs(GL_TRIANGLE_FAN);*/
+//
+    //    //tnsUseNoTexture();
+        //tnsColor4dv(LA_THEME_GET(bt, LA_UI_NORMAL)->BorderColor->RGBA);
+        //tnsVertex2d(ui->L, ui->U);
+        //tnsVertex2d(ui->R, ui->U);
+        //tnsVertex2d(ui->R, ui->B);
+        //tnsVertex2d(ui->L, ui->B);
+        //tnsPackAs(GL_LINE_LOOP);
+//
+    //    //    tnsDrawVectorGraphPackage(ui->SymbolID, LA_THEME_GET(bt, LA_UI_NORMAL), ui->L + HOffset, ui->R, ui->U + VOffset, ui->B, 0, 0);
+    //}
+}
+
+void la_IntDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int Data[32];
+    int Len, i, Seg, W;
+    char buf[48] = {0};
+    char buf2[48] = {0};
+    char prefix[8][64] = {0};
+    int Original;
+    int Ranged;
+    int min, max;
+    int s, State;
+    int IsVertical=ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+    int IsIcon=ui->Flags&LA_UI_FLAGS_ICON;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if (laIsPropertyReadOnly(&ui->PP) && !NoDecal) ui->State = LA_BT_DISABLED;
+
+    laGetIntArray(&ui->PP, Data);
+    Len = laGetArrayLength(&ui->PP);
+
+    laGetPrefixP(&ui->PP, prefix);
+    Ranged = laGetIntRange(&ui->PP, &min, &max);
+
+    for (i = 0; i < Len; i++){
+        int _L=ui->L, _R=ui->R, _U=ui->U, _B=ui->B;
+        if(IsVertical){
+            Seg = ui->R - ui->L;
+            _U = ui->U + i * LA_RH; _B = _U+Seg * LA_RH;
+        }else{
+            Seg = (ui->R - ui->L) / Len;
+            _L = ui->L + i * Seg; _R=_L+Seg;
+        }
+
+        if(IsIcon){
+            sprintf(buf, "%lc", laGetInt(&ui->PP));
+        }else{
+            buf[0] = L'\0'; 
+            strPrintIntAfter(buf, 48, Data[i]);
+            strAppend(buf, ui->PP.LastPs->p->Unit ? transLate(ui->PP.LastPs->p->Unit) : "");
+            buf2[0] = L'\0'; if(Len==1){ strcat(buf2, transLate(ui->PP.LastPs->p->Name)); }
+            if(i<8)strcat(buf2, &prefix[i]);
+        }
+
+        if (ui->Extra && ui->Extra->On == i + 1){
+            Original = ui->State;
+            ui->State = LA_UI_ACTIVE;
+        }
+
+        if(!NoDecal){
+            tnsUseNoTexture();
+            tnsColor4dv(laThemeColor(bt,ui->State));
+            tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+            tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+            tnsPackAs(GL_TRIANGLE_FAN);
+
+            if (Ranged){
+                int L1 = _L;
+                int R1 = (real)(Data[i] - min) / (real)(max - min) * (real)(Seg) + L1;
+                tnsUseNoTexture(); real* color=laThemeColor(bt,LA_BT_TEXT);
+                tnsColor4d(LA_COLOR3(color),0.3);
+                tnsVertex2d(L1, _U); tnsVertex2d(R1, _U);
+                tnsVertex2d(R1, _B); tnsVertex2d(L1, _B);
+                tnsPackAs(GL_TRIANGLE_FAN);
+            }
+
+            tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+            tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+            tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+            tnsPackAs(GL_LINE_LOOP);
+        }
+
+        if (ui->Extra->On == i + 1 && ui->Extra->Edit){
+            uint32_t *buf = strGetCursorLine(ui->Extra->Edit, 0)->Buf;
+            int LL = _L + (Seg - tnsStringGetWidthU(buf, 0, ui->Flags&LA_TEXT_MONO)) / 2;
+            tnsColor4dv(laThemeColor(bt, LA_BT_TEXT));
+            la_SingleLineStringDrawSelection(ui, _L, _U, bt, buf, ui->Extra->Edit);
+
+            tnsDrawStringM(0, buf, laThemeColor(bt, LA_BT_TEXT_ACTIVE), _L + bt->LM, _R - bt->RM, _U, ui->Flags);
+        }else{
+            tnsDrawStringWithPriority(buf2, buf, laThemeColor(bt, LA_BT_TEXT|ui->State), bt->TextAlign, _L + bt->LM, _R - bt->RM, _U, ui->Flags);//, ui->ExtraInstructions);
+        }
+        if (ui->Extra && ui->Extra->On == i + 1) ui->State = Original;
+    }
+
+    tnsFlush();
+}
+void la_FloatDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    real Data[32];
+    int Len, i, W, Seg;
+    char buf[48] = {0};
+    char buf2[48] = {0};
+    char prefix[8][64] = {0};
+    int Original;
+    int Ranged;
+    real min, max;
+    int s, State;
+    int IsVertical=ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if (laIsPropertyReadOnly(&ui->PP) && !NoDecal) ui->State = LA_BT_DISABLED;
+
+    laGetFloatArray(&ui->PP, Data);
+    Len = laGetArrayLength(&ui->PP);
+
+    laGetPrefixP(&ui->PP, prefix);
+    Ranged = laGetFloatRange(&ui->PP, &min, &max);
+
+    for (i = 0; i < Len; i++){
+        int _L=ui->L, _R=ui->R, _U=ui->U, _B=ui->B;
+        if(IsVertical){
+            Seg = ui->R - ui->L;
+            _U = ui->U + i * LA_RH; _B = _U+LA_RH;
+        }else{
+            Seg = (ui->R - ui->L) / Len;
+            _L = ui->L + i * Seg; _R=_L+Seg;
+        }
+
+        buf[0] = L'\0';
+        strPrintFloatAfter(buf, 48, 3, Data[i]);
+        strAppend(buf, ui->PP.LastPs->p->Unit ? transLate(ui->PP.LastPs->p->Unit) : "");
+        buf2[0] = L'\0'; if(Len==1){ strcat(buf2, transLate(ui->PP.LastPs->p->Name)); }
+        if(i<8)strcat(buf2, &prefix[i]);
+
+        if (ui->Extra && ui->Extra->On == i + 1){
+            Original = ui->State;
+            ui->State = LA_UI_ACTIVE;
+        }
+
+        if(!NoDecal){
+            tnsUseNoTexture();
+            tnsColor4dv(laThemeColor(bt,ui->State));
+            tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+            tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+            tnsPackAs(GL_TRIANGLE_FAN);
+
+            if (Ranged){
+                int L1 = _L;
+                int R1 = (real)(Data[i] - min) / (real)(max - min) * (real)(Seg) + L1;
+                tnsUseNoTexture(); real* color=laThemeColor(bt,LA_BT_TEXT);
+                tnsColor4d(LA_COLOR3(color),0.3);
+                tnsVertex2d(L1, _U); tnsVertex2d(R1, _U);
+                tnsVertex2d(R1, _B); tnsVertex2d(L1, _B);
+                tnsPackAs(GL_TRIANGLE_FAN);
+            }
+
+            tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+            tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+            tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+            tnsPackAs(GL_LINE_LOOP);
+        }
+
+        if (ui->Extra->On == i + 1 && ui->Extra->Edit){
+            uint32_t *buf = strGetCursorLine(ui->Extra->Edit,0)->Buf;
+            int LL = _L + (Seg - tnsStringGetWidthU(buf, 0, ui->Flags&LA_TEXT_MONO)) / 2;
+            tnsColor4dv(laThemeColor(bt, LA_BT_TEXT));
+            la_SingleLineStringDrawSelection(ui, _L, _U, bt, buf, ui->Extra->Edit);
+
+            tnsDrawStringM(0, buf, laThemeColor(bt, LA_BT_TEXT_ACTIVE), _L + bt->LM, _R - bt->RM, _U, ui->Flags);
+        }else{
+            tnsDrawStringWithPriority(buf2, buf, laThemeColor(bt, LA_BT_TEXT|ui->State), bt->TextAlign, _L + bt->LM, _R - bt->RM, _U, ui->Flags);//, ui->ExtraInstructions);
+        }
+        if (ui->Extra && ui->Extra->On == i + 1) ui->State = Original;
+    }
+
+    tnsFlush();
+}
+void la_FloatArrayColorDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    real Data[32];
+    int Len, i, Y = ui->U;
+
+    laGetFloatArray(&ui->PP, Data);
+    tnsLogToLinear(Data, MAIN.Gamma);
+    Len = laGetArrayLength(&ui->PP);
+
+    tnsUseNoTexture();
+    tnsColor4d(Data[0], Data[1], Data[2], /*Len>3?Data[4]:*/ 1);
+    tnsVertex2d(ui->L, Y);
+    tnsVertex2d(ui->R, Y);
+    tnsVertex2d(ui->R, Y + h);
+    tnsVertex2d(ui->L, Y + h);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertex2d(ui->L, Y);
+    tnsVertex2d(ui->R, Y);
+    tnsVertex2d(ui->R, Y + h);
+    tnsVertex2d(ui->L, Y + h);
+    tnsPackAs(GL_LINE_LOOP);
+
+    tnsFlush();
+}
+void la_EnumSelectorDraw(laUiItem *ui, int h){
+    laEnumItem *Data[32], Len;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    char buf[48] = {0};
+    char buf2[48] = {0};
+    char prefix[8][64]= {0};
+    laEnumProp *ep = ui->PP.LastPs->p;
+    int HasIcon = laEnumHasIcon(&ui->PP);
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+    int IconOnly=ui->Flags&LA_UI_FLAGS_ICON;
+    int NoEvent=ui->Flags&LA_UI_FLAGS_NO_EVENT;
+    int Highlight=ui->Flags&LA_UI_FLAGS_HIGHLIGHT;
+    // norm      e1
+    // expand    e1 e2 e3
+    // expand vertical  (vertical)
+    // arr expand    e1 e1 e3
+    //               e2 e2 e3
+    // arr exp+vert  e1 e1
+    //               e2 e2
+    //               e3 e3
+
+    tnsUseNoTexture();
+
+    laGetEnumArray(&ui->PP,Data);
+    laEnumItem* ei, *use_ei;
+
+    int IsVertical = ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+    int IsExpand = ui->Flags&LA_UI_FLAGS_EXPAND;
+    int IsCycle = ui->Flags&LA_UI_FLAGS_CYCLE;
+    int ArrLen = laGetArrayLength(&ui->PP);
+    if(ArrLen==1){ if(!IsExpand) IsVertical=0; }else{ IsExpand=1; }
+    int EnumLen = (IsExpand&&(!IsCycle)) ? laGetEnumEntryLen(&ui->PP) : 1;
+
+    if(Highlight&&ArrLen!=1){laGetPrefixP(&ui->PP, prefix);}
+
+    if (laIsPropertyReadOnly(&ui->PP) && !NoDecal) ui->State = LA_BT_DISABLED;
+
+    int _L,_R,_U,_B, _W=ui->R - ui->L;
+    if(IsVertical){
+        if(IsExpand){ _W/=ArrLen; }
+    }else{
+        if(IsExpand){ _W/=EnumLen; }
+        else{ _W/=ArrLen; }
+    }
+    for(int i=0;i<ArrLen;i++){
+        _L=ui->L; _R=ui->R; _U=ui->U; _B=ui->B; ei = ep->Items.pFirst;
+        for(int j=0;j<EnumLen;j++){
+            if(IsVertical){
+                if(IsExpand){ _U=ui->U+j*LA_RH; _L=ui->L+i*_W; }
+                else{ _U=ui->U+i*LA_RH;  _L=ui->L; }
+            }else{
+                if(IsExpand){ _U=ui->U+i*LA_RH;  _L=ui->L+j*_W; }
+                else{ _U=ui->U; _L=ui->L+i*_W; }
+            }
+            _B=_U+LA_RH; _R=_L+_W;
+
+            int ExtraState=ui->State;
+            if(IsExpand&&!IsCycle){ use_ei = ei; ei=ei->Item.pNext; ExtraState=(use_ei==Data[i])?LA_BT_ACTIVE:0; }
+            else{ use_ei = Data[i]; if(Highlight && Data[i]->Index!=0){ ExtraState=LA_BT_ACTIVE; } }
+
+            if(!NoDecal){
+                tnsUseNoTexture();
+                tnsColor4dv(laThemeColor(bt, ExtraState));
+                tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+                tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+                tnsPackAs(GL_TRIANGLE_FAN);
+
+                tnsColor4dv(laThemeColor(bt, LA_BT_BORDER));
+                tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+                tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+                tnsPackAs(GL_LINE_LOOP);
+            }
+
+            if(!Highlight){ strcpy(buf, transLate(use_ei->Name)); }
+            else{ if(ArrLen==1) strcpy(buf, transLate(ui->PP.LastPs->p->Name)); else{ if(i<8)strcat(buf, &prefix[i]); } }
+            int iconR; if(IconOnly)iconR=TNS_MAX2(_L+LA_RH,_R);else{ iconR=TNS_MIN2(_L+LA_RH,_R); }
+            if (use_ei->IconID) tnsDrawIcon(use_ei->IconID, laThemeColor(bt, LA_BT_TEXT|ExtraState), _L,iconR, _U, LA_TEXT_ALIGN_CENTER);
+            if(!IconOnly){
+                int UseFlags=ui->Flags; if(!HasIcon && IsExpand){ if(!(UseFlags&LA_TEXT_ALIGN)); UseFlags|=LA_TEXT_ALIGN_CENTER; }
+                tnsDrawStringAuto(buf, laThemeColor(bt, LA_BT_TEXT|ExtraState), _L+bt->LM+(HasIcon?LA_RH:0), _R-bt->RM, _U, UseFlags);
+            }
+            if (!IsExpand && !IsVertical && !IconOnly && !IsCycle && !NoEvent){
+                tnsDrawIcon(L'▼', laThemeColor(bt, LA_BT_TEXT|ExtraState), _R-LA_RH, _R, _U, ui->Flags);
+            }
+        }
+    }
+    tnsFlush();
+}
+void la_ButtonDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    char buf[LA_RAW_CSTR_MAX_LEN] = {0};
+    char *label = 0;
+    uint32_t IconID=0;
+    int L;
+    char *Identifier;
+    laOperatorProp *ap = 0;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+    int IconOnly=ui->Flags&LA_UI_FLAGS_ICON;
+    int IsHighlight=ui->Flags&LA_UI_FLAGS_HIGHLIGHT;
+
+    if (ui->PP.LastPs && ui->PP.LastPs->p){
+        ap = ui->PP.LastPs->p;
+        label = transLate(ap->Base.Name);
+        if (!ap->OperatorType) ap->OperatorType = laGetOperatorType(ap->OperatorID);
+        IconID = ap->Base.IconID ? ap->Base.IconID : ap->OperatorType->IconID;
+    }else{
+        label = transLate(ui->AT->Name);
+        IconID = ui->AT->IconID;
+    }
+
+    if (ui->AT && (!laOperatorAvailableP(ui->AT, 0, ui->Instructions)))
+        ui->State = LA_UI_DISABLED;
+    elif (ap && ap->OperatorType && (!laOperatorAvailablePSafe(ap->OperatorType, ui->PP.RawThis, ui->PP.Go->UseInstance, ui->Instructions))) ui->State = LA_UI_DISABLED;
+    else if (ui->State == LA_UI_DISABLED) ui->State = LA_UI_NORMAL;
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(ui->State==LA_UI_NORMAL?(IsHighlight?laAccentColor(LA_BT_NORMAL):laThemeColor(bt, ui->State)):laThemeColor(bt, ui->State));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt, LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    if (ui->ExtraInstructions){
+        uint32_t tIconID=0;
+        if (ui->AT && ui->AT->ParseArgs){
+            ui->AT->ParseArgs(ui->Instructions, &tIconID, buf);
+            if (buf[0]) label = buf;
+            if (tIconID) IconID=tIconID;
+        }else if (ui->PP.LastPs->p->PropertyType == LA_PROP_OPERATOR){
+            laOperatorProp *ap = ui->PP.LastPs->p;
+            if (ap->OperatorType && ap->OperatorType->ParseArgs){
+                ap->OperatorType->ParseArgs(ui->Instructions, &tIconID, buf);
+                if (buf[0]) label = buf;
+                if (tIconID) IconID=tIconID;
+            }
+        }
+    }
+
+    if (IconID) L = ui->L + bt->LM  + h;
+    else L = ui->L + bt->LM;
+
+    if (IconID) tnsDrawIcon(IconID, laThemeColor(bt, ui->State|LA_BT_TEXT), ui->L, ui->L+LA_RH, ui->U, LA_TEXT_ALIGN_CENTER);
+
+    if (!IconOnly) tnsDrawStringAuto(label, laThemeColor(bt, ui->State|LA_BT_TEXT), L, ui->R-bt->RM, ui->U, ui->Flags);
+}
+void la_LabelDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int IsDisabled=ui->Flags&LA_UI_FLAGS_DISABLED;
+    int IsHighlight=ui->Flags&LA_UI_FLAGS_HIGHLIGHT;
+
+    if (!ui->State) ui->State = LA_UI_NORMAL;
+    if (ui->ExtraInstructions && !ui->Instructions){
+        strMakeInstructions(&ui->Instructions, ui->ExtraInstructions->Ptr);
+    }
+
+    //int State = ui->Instructions ? (strArgumentMatch(ui->Instructions, "disabled", "true") ? LA_THEME_DISABLED : LA_UI_NORMAL) : LA_UI_NORMAL;
+
+    tnsDrawStringAuto(transLate(ui->Display->Ptr),
+        IsDisabled?laThemeColor(bt,LA_BT_TEXT|LA_UI_DISABLED):(IsHighlight?laAccentColor(LA_BT_TEXT):laThemeColor(bt,LA_BT_TEXT)),
+        ui->L, ui->R, ui->U, ui->Flags);
+}
+void la_SingleLineStringDrawSelection(laUiItem *ui, int Begin, int U, laBoxedTheme *bt, uint32_t *str, laStringEdit *se){
+    tnsUseNoTexture();
+    if (!strHasSelection(se)){
+        tnsColor4dv(laAccentColor(LA_BT_TEXT));
+        int L = (se->CursorBefore ? tnsStringGetWidthU(str, se->CursorBefore, ui->Flags&LA_TEXT_MONO) : 0) + Begin + bt->LM;
+        tnsVertex2d(L-1, U + LA_RH - bt->BM);
+        tnsVertex2d(L-1, U + bt->TM);
+        tnsVertex2d(L+2, U + bt->TM);
+        tnsVertex2d(L+2, U + LA_RH - bt->BM);
+        tnsPackAs(GL_TRIANGLE_FAN);
+    }else{
+        int L = (se->BeginBefore ? tnsStringGetWidthU(str, se->BeginBefore, ui->Flags&LA_TEXT_MONO) : 0) + Begin + bt->LM;
+        int R = (se->EndBefore ? tnsStringGetWidthU(str, se->EndBefore, ui->Flags&LA_TEXT_MONO) : 0) + Begin + bt->LM;
+        tnsColor4dv(laAccentColor(LA_BT_NORMAL));
+        tnsVertex2d(L, U + bt->TM);
+        tnsVertex2d(L, U + LA_RH - bt->BM);
+        tnsVertex2d(R, U + LA_RH - bt->TM);
+        tnsVertex2d(R, U + bt->BM);
+        tnsPackAs(GL_TRIANGLE_FAN);
+    }
+}
+void la_SingleLineStringDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    char* _temp[LA_RAW_CSTR_MAX_LEN] = {0}; char* temp=_temp;
+    uint32_t* line=0;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if (!ui->State) ui->State = LA_UI_NORMAL;
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt, ui->State));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt, LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    if (ui->Extra && ui->Extra->Edit){
+        line=strGetCursorLine(ui->Extra->Edit,0)->Buf;
+    }else{
+        laGetString(&ui->PP, _temp, &temp);
+    }
+
+    if (line) la_SingleLineStringDrawSelection(ui, ui->L+(NoDecal?0:bt->LM), ui->U, bt, line, ui->Extra->Edit);
+
+    tnsColor4dv(laThemeColor(bt, LA_BT_TEXT));
+
+    tnsDrawStringAutoM(line?0:temp, line, laThemeColor(bt, LA_BT_TEXT), ui->L+(NoDecal?0:bt->LM), ui->R-(NoDecal?0:bt->RM), ui->U, ui->Flags);
+}
+void la_MultiStringDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    char _temp[LA_RAW_CSTR_MAX_LEN] = {0}; char* temp=_temp;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if (!ui->State) ui->State = LA_UI_NORMAL;
+
+    int NumberWidth=bt->LM;
+
+
+    if(!ui->Extra->Edit){
+        laGetString(&ui->PP, _temp, &temp);
+        strBeginEdit(&ui->Extra->Edit, temp);
+    }
+
+    laStringEdit* se=ui->Extra->Edit;
+    int MonoWidth=tnsGetMonoFontAdvance(); int Count=se->TotalLines;
+    while(Count){ Count/=10; NumberWidth+=MonoWidth; }
+
+    if (ui->State!=LA_UI_ACTIVE){
+        strSetEditViewRange(ui->Extra->Edit,ui->Extra->HeightCoeff,(ui->R-ui->L-NumberWidth-bt->LM*2-bt->RM)/MonoWidth);
+    }
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt, ui->State));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt, LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+
+        tnsColor4d(LA_COLOR3(laThemeColor(bt,LA_BT_BORDER)),0.8);
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->L+NumberWidth, ui->U);
+        tnsVertex2d(ui->L, ui->B); tnsVertex2d(ui->L+NumberWidth, ui->B);
+        tnsPackAs(GL_QUADS);
+
+        if(!(se->CursorLine<se->ViewStartLine||se->CursorLine>se->ViewStartLine+se->ViewHeight)){
+            int LineU=(se->CursorLine-se->ViewStartLine)*LA_RH+ui->U;
+            tnsColor4dv(ui->State==LA_UI_ACTIVE?laAccentColor(LA_BT_NORMAL):laThemeColor(bt,LA_BT_BORDER));
+            tnsVertex2d(ui->L, LineU); tnsVertex2d(ui->R, LineU);
+            tnsVertex2d(ui->L, LineU+LA_RH); tnsVertex2d(ui->R, LineU+LA_RH);
+            tnsPackAs(GL_LINES);
+
+            tnsColor4dv(ui->State==LA_UI_ACTIVE?laAccentColor(LA_BT_TEXT):laThemeColor(bt,LA_BT_TEXT_NORMAL));
+            tnsVertex2d(ui->L, LineU); tnsVertex2d(ui->L+NumberWidth, LineU);
+            tnsVertex2d(ui->L, LineU+LA_RH); tnsVertex2d(ui->L+NumberWidth, LineU+LA_RH);
+            tnsPackAs(GL_QUADS);
+        }
+    }else{
+        NumberWidth=bt->LM;
+    }
+
+    tnsColor4dv(laThemeColor(bt, LA_BT_TEXT));
+
+    int Line=0, Skip=0, _L=ui->L+NumberWidth+bt->LM; char num[10]={0};
+    for(laStringLine* sl=se->Lines.pFirst;sl;sl=sl->Item.pNext){
+        int UseLine=Line+Skip;
+        if(UseLine<se->ViewStartLine){ Skip++; continue; }
+        if(UseLine>=se->ViewHeight+se->ViewStartLine){ break; }
+        int slen=strlenU(sl->Buf);
+        sprintf(num,"%d", UseLine+1); int LineU=ui->U+Line*LA_RH;
+        tnsDrawStringM(num, 0, laThemeColor(bt, ((UseLine==se->CursorLine)?LA_BT_NORMAL:LA_BT_TEXT)),
+             _L-bt->LM -(tnsStringGetWidth(num, 0, ui->Flags&LA_TEXT_MONO)), ui->R, LineU, ui->Flags);
+        if(slen>=se->ViewStartCol){
+            tnsDrawStringM(0, &sl->Buf[se->ViewStartCol], laThemeColor(bt, ui->State|LA_BT_TEXT), _L, ui->R, LineU, ui->Flags|LA_TEXT_OVERFLOW_ARROW);
+        }
+        if(UseLine>=se->BeginLine&&UseLine<=se->EndLine){
+            int BeginC=UseLine==se->BeginLine?se->BeginBefore:0; int EndC=UseLine==se->EndLine?se->EndBefore:slen; 
+            BeginC-=se->ViewStartCol; EndC-=se->ViewStartCol; if(EndC>se->ViewWidth)EndC=se->ViewWidth;
+            tnsUseNoTexture();
+            tnsVertex2d(BeginC*MonoWidth+_L, LineU);     tnsVertex2d(EndC*MonoWidth+_L, LineU);
+            tnsVertex2d(EndC*MonoWidth+_L, LineU+LA_RH); tnsVertex2d(BeginC*MonoWidth+_L, LineU+LA_RH);
+            tnsColor4dv(laAccentColor(LA_BT_NORMAL));
+            tnsPackAs(GL_TRIANGLE_FAN);
+        }
+        int len=strlenU(sl->Buf); 
+        if(UseLine==se->CursorLine){
+            int Dist=se->CursorBefore==0?0:tnsStringGetWidthU(sl->Buf,se->CursorBefore,ui->Flags&LA_TEXT_MONO);
+            tnsUseNoTexture(); int d=se->ViewStartCol*MonoWidth;
+            tnsColor4dv(ui->State==LA_UI_ACTIVE?laAccentColor(LA_BT_TEXT):laThemeColor(bt,LA_BT_TEXT_NORMAL));
+            tnsVertex2d(_L+Dist-d, LineU); tnsVertex2d(_L+Dist+3-d, LineU);
+            tnsVertex2d(_L+Dist-d, LineU+LA_RH); tnsVertex2d(_L+Dist+3-d, LineU+LA_RH);
+            tnsPackAs(GL_QUADS);
+        }
+        Line++;
+        tnsFlush();
+    }
+
+    if(ui->Extra->HeightCoeff>=0)
+        tnsDrawStringAuto("◿",laThemeColor(bt,LA_BT_BORDER),ui->R-LA_RH, ui->R, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+
+    if(!NoDecal){
+        char buf[100]={0}; sprintf(buf, "%d,%d | %d Lines", se->CursorLine+1, se->CursorBefore+1, se->TotalLines);
+        tnsDrawStringAuto(buf,laThemeColor(bt,LA_BT_BORDER),ui->L, ui->R-LA_RH, ui->B-bt->BM-LA_RH, LA_TEXT_MONO|LA_TEXT_ALIGN_RIGHT);
+    }
+    
+    //if (ui->Extra && ui->Extra->Edit) la_SingleLineStringDrawSelection(ui, ui->L, ui->U, bt, temp, ui->Extra->Edit);
+
+    tnsFlush();
+}
+void la_UiSeperatorDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    if (!bt) return;
+
+    if(ui->Flags&LA_UI_FLAGS_TRANSPOSE){
+        char str[]="🞄";
+        int strw=tnsStringGetWidth(str,0, 0);
+        tnsDrawStringM(str, 0, laThemeColor(bt,LA_BT_BORDER), ui->L+(ui->R-ui->L-strw)/2, ui->R, ui->U, 0);
+    }else{
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsPackAs(GL_LINES);
+    }
+}
+void la_ColorCircleDrawHCY(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    real c = (real)((ui->R + ui->L) / 2) - h / 2; /*- bt->RM*/
+    ;
+    real r = (ui->B - ui->U - bt->TP - bt->BP) / 2;
+    int i = 0;
+    real colors[296]; //4*74
+    real verts[148];
+    real hcy[3] = {0, 1, 1};
+    real step = 1.0 / 72.0f;
+    real RealColor[4] = {0};
+    real PickerPos[2];
+    real pi_4;
+    GLuint index[26];
+    real v, cv, sv;
+
+    laGetFloatArray(&ui->PP, RealColor);
+
+    if (MAIN.ColorAccessCorrectGamma) {
+        tnsLogToLinear(RealColor, MAIN.Gamma);
+    }
+
+    tnsRGBtoHCY(RealColor, hcy);
+
+    //if (MAIN.ColorAccessCorrectGamma) {
+    //    tnsSingleLinearToLog(&hcy[2], MAIN.Gamma);
+    //}
+
+    //tnsSingleLinearToLog(&hcy[1], 2.2);
+
+    PickerPos[0] = c + cos(hcy[0] * TNS_PI * 2) * hcy[1] * r;
+    PickerPos[1] = ui->U + r + sin(hcy[0] * TNS_PI * 2) * hcy[1] * r;
+
+    hcy[1] = 1;
+    hcy[0] = 0;
+
+    for (i; i < 72; i += 1){
+        int beg = 4 + i * 4;
+        hcy[0] += step;
+        tnsHCYtoRGB(hcy, &colors[beg]);
+        //tnsLinearToLog(&colors[beg], MAIN.Gamma);
+        colors[beg + 3] = 1;
+    }
+    
+    tnsUseNoTexture();
+    colors[0] = colors[1] = colors[2] = hcy[2];
+    colors[3] = 1;
+    colors[292] = colors[4];
+    colors[293] = colors[5];
+    colors[294] = colors[6];
+    colors[295] = colors[7];
+    tnsColorArray4d(colors, 74);
+    tnsMakeCircle2d(&verts[2], 72, c, ui->U + r, r);
+    verts[0] = c;
+    verts[1] = ui->U + r;
+    verts[146] = verts[2];
+    verts[147] = verts[3];
+    tnsVertexArray2d(verts, 74);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertexArray2d(&verts[4], 72);
+    tnsPackAs(GL_LINE_LOOP);
+
+    tnsColor4dv(RealColor);
+    tnsMakeCircle2d(verts, 16, PickerPos[0], PickerPos[1], 8);
+    tnsVertexArray2d(verts, 16);
+    tnsPackAs(GL_TRIANGLE_FAN);
+    tnsColor4d(1, 1, 1, 1);
+    tnsVertexArray2d(verts, 16);
+    tnsPackAs(GL_LINE_LOOP);
+    tnsMakeCircle2d(verts, 16, PickerPos[0], PickerPos[1], 7);
+    tnsColor4d(0.1, 0.1, 0.1, 1);
+    tnsVertexArray2d(verts, 16);
+    tnsPackAs(GL_LINE_LOOP);
+
+    pi_4 = TNS_PI / 4;
+
+    tnsMakeArc2d(&verts[26], 12, c, ui->U + r, r + bt->LM + h, pi_4, -pi_4);
+    tnsMakeArc2d(verts, 12, c, ui->U + r, r + bt->LM, pi_4, -pi_4);
+    tnsMakeLinerGradient4d(&colors[52], 13, 0, 0, 0, 1, 1, 1, 1, 1);
+    tnsMakeLinerGradient4d(colors, 13, 0, 0, 0, 1, 1, 1, 1, 1);
+    tnsMakeBridgedIndex(index, 13, 0, 0);
+    tnsColorArray4d(colors, 26);
+    tnsVertexArray2d(verts, 26);
+    tnsIndexArray(index, 26);
+    tnsPackAs(GL_QUAD_STRIP);
+
+    tnsMakeArc2d(&verts[26], 12, c, ui->U + r, r + bt->LM + h, -pi_4, pi_4);
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertexArray2d(verts, 26);
+    tnsPackAs(GL_LINE_LOOP);
+
+    v = -hcy[2] + 0.5;
+    cv = cos(v / 2 * TNS_PI);
+    sv = sin(v / 2 * TNS_PI);
+
+    verts[0] = cv * r + c;
+    verts[1] = sv * r + ui->U + r;
+    verts[2] = cv * (r + h) + c;
+    verts[3] = sv * (r + h) + ui->U + r;
+    tnsColor4d(1, 1, 1, 1);
+    tnsVertexArray2d(verts, 2);
+    tnsPackAs(GL_LINES);
+
+    tnsFlush();
+}
+void la_MenuItemDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt, ui->State));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+        tnsColor4dv(laThemeColor(bt, LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+    tnsDrawStringAuto(transLate(ui->Display->Ptr), laThemeColor(bt, LA_BT_TEXT|ui->State), ui->L+bt->LM, ui->R, ui->U, ui->Flags);
+}
+void la_ConditionToggleDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    char temp[128] = {0};
+    char *buf[LA_RAW_CSTR_MAX_LEN];
+    uint32_t IconID;
+    int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL;
+
+    if (!ui->State) ui->State = LA_UI_NORMAL;
+    int UseState=ui->State;
+    if (!(ui->Flags&LA_TEXT_ALIGN)) ui->Flags|=LA_TEXT_ALIGN_CENTER;
+
+    if(!NoDecal){
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt, ui->State));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt, LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }else{
+        UseState=LA_UI_NORMAL;
+    }
+
+
+    buf[0] = 0;
+    if (ui->ExtraInstructions){
+        if (ui->Type->OperatorType->ParseArgs){
+            ui->Type->OperatorType->ParseArgs(ui->Instructions, &IconID, buf);
+        }
+    }
+    if (buf[0]) tnsDrawStringAuto(transLate(buf), laThemeColor(bt, LA_BT_TEXT|UseState), ui->L+bt->LM, ui->R-bt->RM, ui->U, ui->Flags);
+    else
+        tnsDrawStringAuto(ui->State == LA_UI_ACTIVE ? "⯆" : "⯈", laThemeColor(bt, LA_BT_TEXT|UseState), ui->L+bt->LM, ui->R-bt->RM, ui->U, ui->Flags);
+}
+void la_DrawColumnAdjusterRecursive(int U, int B, laColumn *c, int W, tnsVector3d color, int LeftMost){
+    if (c->LS){
+        la_DrawColumnAdjusterRecursive(U, B, c->LS, W, color, LeftMost);
+        la_DrawColumnAdjusterRecursive(U, B, c->RS, W, color, LeftMost);
+    }else{
+        if(c->IL==LeftMost) return;
+        tnsDrawStringAuto("❘", color, c->IL-LA_RH, c->IL+LA_RH, U, LA_TEXT_ALIGN_CENTER);
+    }
+}
+void la_ColumnAdjusterDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+
+    tnsUseNoTexture();
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    la_DrawColumnAdjusterRecursive(ui->U, ui->U + LA_RH, ui->C, (bt->LM+bt->RM)/2, laThemeColor(bt, LA_BT_BORDER), ui->C->IL);
+}
+void la_ColumnViewerDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laColumn *c = ui->PP.EndInstance;
+    int W = ui->R - ui->L - bt->LM - bt->RM;
+    //if (c->IR == c->IL)
+    //    return;
+    int T = c->Top->IR - c->Top->IL;
+    int L = (int)((real)(c->IL - c->Top->IL) * W / T) + ui->L + bt->LM,
+        R = (int)((real)(c->IR - c->Top->IL) * W / T) + ui->L + bt->LM;
+
+    tnsUseNoTexture();
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+
+    tnsVertex2d(L, ui->U + bt->TM);
+    tnsVertex2d(R, ui->U + bt->TM);
+    tnsVertex2d(R, ui->B - bt->BM);
+    tnsVertex2d(L, ui->B - bt->BM);
+    tnsPackAs(GL_TRIANGLE_FAN);
+}
+void la_NodeSocketDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    char* label=0; char* icon;
+    laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);
+    real* ColorBkg=0,*ColorSocket;
+    if(pc==LA_PC_SOCKET_IN)   { laNodeInSocket*s=ui->PP.EndInstance; ColorSocket=laThemeColor(bt,LA_BT_TEXT);}
+    elif(pc==LA_PC_SOCKET_OUT){ laNodeOutSocket*s=ui->PP.EndInstance; ColorSocket=laThemeColor(bt,LA_BT_TEXT_ACTIVE); ColorBkg=laThemeColor(bt, LA_BT_ACTIVE); }
+
+    int IsDisabled=ui->Flags&LA_UI_FLAGS_DISABLED;
+
+    if(ColorBkg){
+        tnsUseNoTexture();
+        tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B);
+        tnsColor4dv(ColorBkg);
+        tnsPackAs(GL_TRIANGLE_FAN);
+    }
+
+    tnsDrawStringAuto("⭗", IsDisabled?laThemeColor(bt,LA_BT_TEXT|LA_UI_DISABLED):ColorSocket, ui->L, ui->R, ui->U, LA_TEXT_ALIGN_CENTER);
+}
+void la_HeightAdjusterDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    tnsDrawStringAuto("◸", laThemeColor(bt,LA_BT_BORDER), ui->L, ui->R, ui->U, LA_TEXT_ALIGN_CENTER);
+}
+void la_RawPropDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int s=0;
+    //void* data=laGetRaw(&ui->PP, &s);
+    //char* buf[128]; sprintf(buf,"%d bytes of raw data at 0x%0x", s, data);
+    tnsDrawStringAuto("RAW DATA", laThemeColor(bt,LA_BT_TEXT), ui->L, ui->R, ui->U, ui->Flags|LA_TEXT_MONO);
+}
+
+void la_IntMeterDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int Data[32];
+    int Len, i, W; real Seg;
+    char buf[48] = {0};
+    char buf2[48] = {0};
+    char prefix[8][64] = {0};
+    int Original;
+    int min=-100, max=100;
+    int s, State;
+    int IsVertical=ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+
+    laGetIntArray(&ui->PP, Data);
+    Len = laGetArrayLength(&ui->PP);
+
+    laGetPrefixP(&ui->PP, prefix);
+    laGetIntRange(&ui->PP, &min, &max);
+
+    for (i = 0; i < Len; i++){
+        int _L=ui->L, _R=ui->R, _U=ui->U, _B=ui->B;
+        if(IsVertical){
+            Seg = (real)(ui->R-ui->L)/Len;
+            _L = ui->L + i * Seg; _R=ui->L + (i+1) * Seg;
+        }else{
+            Seg = (real)(ui->B-ui->U)/Len;
+            _U = ui->U + i * Seg; _B=_U+Seg;
+        }
+
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,ui->State));
+        tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+        tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        int R1=_R,U1=_U;
+        if(IsVertical){ U1 = (real)(max - Data[i]) / (real)(max - min) * (real)(_B-_U) + _U; }
+        else{ R1 = (real)(Data[i] - min) / (real)(max - min) * (real)(_R-_L) + _L; }
+        tnsUseNoTexture(); real* color=laThemeColor(bt,LA_BT_TEXT);
+        tnsColor4d(LA_COLOR3(color),0.4);
+        tnsVertex2d(_L, U1); tnsVertex2d(R1, U1);
+        tnsVertex2d(R1, _B); tnsVertex2d(_L, _B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+        tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+        tnsPackAs(GL_LINE_LOOP);
+
+        if(Len==1){ sprintf(buf,ui->PP.LastPs->p->Name); } else{ if(i<8)sprintf(buf,prefix[i]); }
+
+        tnsDrawStringAuto(buf, laThemeColor(bt, LA_BT_TEXT), _L + bt->LM, _R - bt->RM, _U, ui->Flags);//, ui->ExtraInstructions);
+    }
+
+    tnsFlush();
+}
+void la_IntMeter2DDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int Data[32];
+    int Len, i, W; real Seg;
+    char buf[48] = {0};
+    char buf2[48] = {0};
+    char prefix[8][64] = {0};
+    int Original;
+    int min=-100, max=100;
+
+    laGetIntArray(&ui->PP, Data);
+    Len = laGetArrayLength(&ui->PP);
+
+    laGetPrefixP(&ui->PP, prefix);
+    laGetIntRange(&ui->PP, &min, &max);
+
+    int _L=ui->L, _R=ui->R, _U=ui->U, _B=ui->B;
+
+    tnsUseNoTexture();
+    tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
+    tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+    tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+    tnsPackAs(GL_TRIANGLE_FAN);
+
+    real CL=(real)(Data[0] - min) / (real)(max - min) * (real)(_R-_L) + _L;
+    real CU=(real)(max - Data[1]) / (real)(max - min) * (real)(_B-_U) + _U;
+    real HW=((real)_R-(real)_L)/4; real HH=((real)_B-(real)_U)/4;
+    real ML=((real)_R+(real)_L)/2; real MU=((real)_B+(real)_U)/2;
+
+    tnsUseNoTexture(); real* color=laThemeColor(bt,LA_BT_TEXT);
+    tnsColor4d(LA_COLOR3(color),0.4);
+    tnsVertex2d(ML+HW, MU+HH); tnsVertex2d(ML-HW, MU+HH);
+    tnsVertex2d(ML-HW, MU-HH); tnsVertex2d(ML+HW, MU-HH);
+    tnsPackAs(GL_LINE_LOOP);
+    tnsVertex2d(_L,_U); tnsVertex2d(_R,_B);
+    tnsVertex2d(_R,_U); tnsVertex2d(_L,_B);
+    tnsVertex2d(ML,_U); tnsVertex2d(ML,_B);
+    tnsVertex2d(_R,MU); tnsVertex2d(_L,MU);
+    tnsPackAs(GL_LINES);
+
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+    tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+    tnsPackAs(GL_LINE_LOOP);
+
+    tnsFlush();
+
+    tnsColor4dv(laThemeColor(bt,LA_BT_TEXT));
+    tnsVertex2d(_L, CU); tnsVertex2d(_R, CU);
+    tnsVertex2d(CL, _U); tnsVertex2d(CL, _B);
+    tnsPackAs(GL_LINES);
+
+    real circle[48];
+    tnsMakeCircle2d(circle,24,CL,CU,LA_RH2);
+    tnsVertexArray2d(circle,24);
+    tnsPackAs(GL_LINE_LOOP);
+
+    glLineWidth(2);
+    tnsFlush();
+    glLineWidth(1);
+}
+
+void la_ConditionNodeFreeRecursive(laUiConditionNode *ucn);
+void la_GeneralUiInit(laUiItem *ui){
+    ui->Extra = memAcquireSimple(sizeof(laGeneralUiExtraData));
+    ui->Extra->ui=ui;
+}
+void la_GeneralUiDestroy(laUiItem *ui){
+    if(ui->Extra && ui->Extra->Edit){ strEndEdit(&ui->Extra->Edit, 1); }
+    memFree(ui->Extra);
+}
+void la_ConditionUiDestroy(laUiItem *ui){
+    laConditionUiExtraData *cued = ui->Extra;
+    la_ConditionNodeFreeRecursive(cued->Expression);
+    FreeMem(ui->Extra);
+}
+void la_MultiStringInit(laUiItem *ui){
+    laGeneralUiExtraData *e = ui->Extra;
+    if (!e) e = memAcquireSimple(sizeof(laGeneralUiExtraData));
+    ui->Extra = e;
+
+    e->HeightCoeff = 10;
+}
+
+void la_RegisterUiTypesBasic(){
+    laKeyMapper* km;
+    laPropContainer* pc;
+
+    LA_WIDGET_INT->Type=LA_WIDGET_INT_PLAIN->Type=
+    _LA_UI_INT = la_RegisterUiType("LA_int_array_horizon", LA_PROP_INT | LA_PROP_ARRAY, "LA_int_array_h_operator",
+                        &_LA_THEME_VALUATOR, la_IntDraw, la_ValueGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_INT->GetMinWidth=la_ValueGetMinWidth;
+
+    LA_WIDGET_INT_METER->Type=
+    _LA_UI_INT_METER = la_RegisterUiType("LA_int_meter", LA_PROP_INT | LA_PROP_ARRAY, 0, &_LA_THEME_VALUATOR, la_IntMeterDraw, la_IntMeterGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_INT_METER_2D->Type=
+    _LA_UI_INT_METER_2D = la_RegisterUiType("LA_int_meter_2d", LA_PROP_INT | LA_PROP_ARRAY, 0, &_LA_THEME_VALUATOR, la_IntMeter2DDraw, la_IntMeter2DGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_FLOAT->Type=LA_WIDGET_FLOAT_PLAIN->Type=
+    _LA_UI_FLOAT = la_RegisterUiType("LA_real_array_horizon", LA_PROP_FLOAT | LA_PROP_ARRAY, "LA_real_array_h_operator",
+                        &_LA_THEME_VALUATOR, la_FloatDraw, la_ValueGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_FLOAT->GetMinWidth=la_ValueGetMinWidth;
+
+    LA_WIDGET_FLOAT_COLOR->Type=
+    _LA_UI_FLOAT_COLOR = la_RegisterUiType("LA_real_color", LA_PROP_FLOAT | LA_PROP_ARRAY, "LA_real_color_operator",
+                        &_LA_THEME_VALUATOR, la_FloatArrayColorDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_FLOAT_HCY->Type=
+    _LA_UI_FLOAT_HCY = la_RegisterUiType("LA_real_hcy", LA_PROP_FLOAT | LA_PROP_ARRAY, "LA_real_hcy_operator",
+                        &_LA_THEME_VALUATOR, la_ColorCircleDrawHCY, la_ColorPickerGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_FLOAT_HCY->GetMinWidth = la_ColorPickerGetMinWidth;
+
+    LA_WIDGET_ENUM_SELECTOR->Type=LA_WIDGET_ENUM_SELECTOR_ICON->Type=LA_WIDGET_ENUM_CYCLE->Type=LA_WIDGET_ENUM_HIGHLIGHT->Type=
+    _LA_UI_ENUM_SELECTOR = la_RegisterUiType("LA_enum_selector", LA_PROP_ENUM, "LA_enum_selector_operator",
+                        &_LA_THEME_SELECTOR, la_EnumSelectorDraw, la_EnumGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_ENUM_SELECTOR->GetMinWidth = la_EnumGetMinWidth;
+
+    LA_WIDGET_FIXED_GROUP->Type=
+    _LA_UI_FIXED_GROUP = la_RegisterUiType("LA_group_default", 0, 0,
+                        &_LA_THEME_COLLECTION_GROUP, la_GroupDraw, la_GroupGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+                        _LA_UI_FIXED_GROUP->Tag|=LA_UI_TAG_SCISSOR;
+
+    LA_WIDGET_COLLECTION->Type=
+    _LA_UI_COLLECTION = la_RegisterUiType("LA_collection_default", LA_PROP_SUB, "LA_collection_operator",
+                        &_LA_THEME_COLLECTION_GROUP, la_EmptyDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_COLLECTION_SELECTOR->Type=
+    _LA_UI_COLLECTION_SELECTOR = la_RegisterUiType("LA_collection_selector_default", LA_PROP_SUB, "LA_collection_selector_operator",
+                        &_LA_THEME_COLLECTION_SELECTOR, la_CollectionSelectorDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_COLLECTION_SINGLE->Type=
+    _LA_UI_COLLECTION_SINGLE = la_RegisterUiType("LA_collection_single", LA_PROP_SUB, "LA_collection_operator",
+                        &_LA_THEME_COLLECTION_GROUP, la_EmptyDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_TAB->Type=
+    _LA_UI_TAB = la_RegisterUiType("LA_tab_default", 0, "LA_tab_operator",
+                        &_LA_THEME_TAB, la_TabDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+
+    LA_WIDGET_BUTTON->Type=LA_WIDGET_BUTTON_NO_CONFIRM->Type=
+    _LA_UI_BUTTON = la_RegisterUiType("LA_button_default", LA_PROP_OPERATOR, "LA_button_operator",
+                        &_LA_THEME_BUTTON, la_ButtonDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_BUTTON->GetMinWidth = la_ButtonGetMinWidth;
+    LA_WIDGET_BUTTON_NO_CONFIRM->Flags|=LA_UI_FLAGS_NO_CONFIRM;
+    pc=laUiHasExtraProps(_LA_UI_BUTTON, sizeof(laGeneralUiExtraData),0);
+
+    LA_WIDGET_LABEL->Type=
+    _LA_UI_LABEL = la_RegisterUiType("LA_label_default", LA_PROP_OPERATOR, 0,
+                        &_LA_THEME_LABEL, la_LabelDraw, la_LabelHeight, 0, 0);
+    _LA_UI_LABEL->GetMinWidth = la_LabelGetMinWidth;
+
+    LA_WIDGET_MENU_ROOT->Type=
+    _LA_UI_MENU_ROOT = la_RegisterUiType("LA_menu_default", LA_PROP_OPERATOR, "LA_menu_root_operator",
+                        &_LA_THEME_BUTTON, la_MenuItemDraw, 0, 0, 0);
+    _LA_UI_MENU_ROOT->GetMinWidth=la_LabelGetMinWidth;
+
+    LA_WIDGET_CONDITION_TOGGLE->Type=
+    _LA_UI_CONDITION_TOGGLE = la_RegisterUiType("LA_condition_toggle_default", LA_PROP_SELF_CONDITION, "LA_condition_toggle_operator",
+                        &_LA_THEME_BUTTON, la_ConditionToggleDraw, 0, 0, 0);
+
+    LA_WIDGET_STRING->Type=LA_WIDGET_STRING_PLAIN->Type=LA_WIDGET_STRING_MONO_PLAIN->Type=
+    _LA_UI_STRING = la_RegisterUiType("LA_string_default", LA_PROP_STRING, "LA_string_operator",
+                        &_LA_THEME_STRING, la_SingleLineStringDraw, la_StringPropGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_STRING->GetMinWidth = la_StringPropGetMinWidth;
+    km=&_LA_UI_STRING->KeyMapper;
+    laAssignNewKey(km, 0, "LA_edit_string_copy", LA_KM_SEL_UI_EXTRA, LA_KEY_CTRL, LA_KEY_DOWN, 'c', 0);
+    laAssignNewKey(km, 0, "LA_system_paste", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'v', 0);
+    pc=laUiHasExtraProps(_LA_UI_STRING, sizeof(laGeneralUiExtraData), 0);{
+        laAddOperatorProperty(pc, "copy_selection", "Copy Selection", "Copy selected string into clipboard", "LA_edit_string_copy",0,0);
+    }
+
+    LA_WIDGET_STRING_MULTI->Type=
+    _LA_UI_STRING_MULTI = la_RegisterUiType("LA_string_multiline", LA_PROP_STRING, "LA_string_multi",
+                        &_LA_THEME_STRING, la_MultiStringDraw, la_MultiStringHeight, la_MultiStringInit, la_GeneralUiDestroy);
+    _LA_UI_STRING_MULTI->GetMinWidth = la_StringPropGetMinWidth;
+    km=&_LA_UI_STRING_MULTI->KeyMapper;
+    laAssignNewKey(km, 0, "LA_edit_string_copy", LA_KM_SEL_UI_EXTRA, LA_KEY_CTRL, LA_KEY_DOWN, 'c', 0);
+    laAssignNewKey(km, 0, "LA_system_paste", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'v', 0);
+    pc=laUiHasExtraProps(_LA_UI_STRING_MULTI, sizeof(laGeneralUiExtraData), 0);{
+        laAddOperatorProperty(pc, "copy_selection", "Copy Selection", "Copy selected string into clipboard", "LA_edit_string_copy",0,0);
+    }
+
+    LA_WIDGET_ALIGN->Type=
+    _LA_UI_ALIGN = la_RegisterUiType("LA_colum_align_default", 0, 0,
+                        &_LA_THEME_BUTTON, la_UiSeperatorDraw, 0, 0, 0);
+
+    LA_WIDGET_COLUMN_ADJUSTER->Type=
+    _LA_UI_COLUMN_ADJUSTER = la_RegisterUiType("LA_column_adjuster_default", 0, "LA_column_adjuster",
+                        &_LA_THEME_BUTTON, la_ColumnAdjusterDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_COLUMN_ADJUSTER->TargetSub = "ui_column";
+
+    LA_WIDGET_COLUMN_VIEWER->Type=
+    _LA_UI_COLUMN_VIEWER = la_RegisterUiType("LA_column_viewer_default", 0, 0,
+                        &_LA_THEME_BUTTON, la_ColumnViewerDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_COLUMN_VIEWER->TargetSub = "ui_column";
+    _LA_UI_COLUMN_VIEWER->GetMinWidth = la_ColumnViewerGetMinWidth;
+
+    _LA_UI_CONDITION_ELSE.Theme = &_LA_THEME_BUTTON;
+    la_UDFAppendSharedTypePointer("LA_condition_else", &_LA_UI_CONDITION_ELSE);
+    _LA_UI_CONDITION.Destroy = la_ConditionUiDestroy;
+    _LA_UI_CONDITION.Theme = &_LA_THEME_BUTTON;
+    la_UDFAppendSharedTypePointer("LA_condition", &_LA_UI_CONDITION);
+    _LA_UI_CONDITION_END.Theme = &_LA_THEME_BUTTON;
+    la_UDFAppendSharedTypePointer("LA_condition_end", &_LA_UI_CONDITION_END);
+
+    LA_WIDGET_SYMBOL->Type=
+    _LA_UI_SYMBOL = la_RegisterUiType("LA_symbol_default", 0, 0, &_LA_THEME_BUTTON, la_SymbolDraw, la_SymbolGetHeight, 0, 0);
+
+    LA_WIDGET_NODE_SOCKET->Type=
+    _LA_UI_NODE_SOCKET = la_RegisterUiType("LA_node_socket_default", 0, "LA_node_socket", &_LA_THEME_SOCKET, la_NodeSocketDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_NODE_SOCKET->GetMinWidth=la_SocketGetMinWidth;
+    
+    LA_WIDGET_HEIGHT_ADJUSTER->Type=
+    _LA_UI_HEIGHT_ADJUSTER = la_RegisterUiType("LA_height_adjuster_default", 0, "LA_height_adjuster", &_LA_THEME_COLLECTION_GROUP, la_HeightAdjusterDraw, 0, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_HEIGHT_ADJUSTER->ForType = LA_PROP_INT;
+
+    LA_WIDGET_RAW->Type=
+    _LA_UI_RAW = la_RegisterUiType("LA_raw_prop_default", 0, 0, &_LA_THEME_COLLECTION_GROUP, la_RawPropDraw, 0, 0, 0);
+    _LA_UI_RAW->ForType = LA_PROP_RAW;
+
+    _LA_UI_ROW_BEGIN.Theme=&_LA_THEME_BUTTON;
+    _LA_UI_ROW_END.Theme=&_LA_THEME_BUTTON;
+}
+
+// ============================================================ [Operators]
+
+void la_DefaultEnumPanel(laUiList *uil, laPropPack *This, laPropPack *OperatorProps, laColumn *UNUSED){
+    laColumn *c = laFirstColumn(uil);
+    laShowItem(uil, c, This, 0)->Flags=(LA_UI_FLAGS_TRANSPOSE|LA_UI_FLAGS_EXPAND);
+}
+
+int la_DetectRow(laUiItem *ui, int LocalY){
+    return (LocalY - ui->U) / LA_RH;
+}
+int la_DetectColumn(laUiItem *ui, int LocalX, int Total){
+    return (int)((real)(LocalX - ui->L) / (real)(ui->R - ui->L) * (real)Total);
+}
+
+laColumn *la_DetectSplit(laColumn *Root, int LocalX){
+    laColumn *result = 0;
+    if (!Root->LS) return 0;
+    if (LocalX - Root->LS->IR < LA_SCROLL_W && Root->LS->IR - LocalX < LA_SCROLL_W &&
+        !Root->LS->MaxW && !Root->RS->MaxW){
+        return Root;
+    }
+    result = la_DetectSplit(Root->LS, LocalX);
+    if (result) return result;
+    else
+        return la_DetectSplit(Root->RS, LocalX);
+}
+void la_AdjustColumnSplit(laColumn *c, int PxLeftPositive){
+    if (!c->LS || c->LS->MaxW || c->RS->MaxW) return;
+    if (PxLeftPositive < 0 && c->LS->IR - c->LS->IL <= LA_SCROLL_W*2) return;
+    if (PxLeftPositive > 0 && c->RS->IR - c->RS->IL <= LA_SCROLL_W*2) return;
+    c->LS->IR += PxLeftPositive;
+    c->RS->IL += PxLeftPositive;
+    c->LS->SP = (real)(c->LS->IR - c->LS->IL) / (real)(c->IR - c->IL);
+    c->RS->SP = c->LS->SP;
+}
+
+int OPCHK_EditStringCopySelection(laPropPack *This, laStringSplitor *Instructions){
+    laGeneralUiExtraData *uit = This->EndInstance; if(!uit) return 0;
+    if(!uit->Edit || !strHasSelection(uit->Edit)) return 0;
+    return 1;
+}
+int OPINV_EditStringCopySelection(laOperator *a, laEvent *e){
+    laGeneralUiExtraData *uit = a->This->EndInstance; if(!uit) return LA_FINISHED;
+    if(!uit->Edit || !strHasSelection(uit->Edit)) return LA_FINISHED;
+
+    char* str=strGetEditString(uit->Edit, 1);
+    laCopyToClipboard(str); free(str);
+
+    return LA_FINISHED;
+}
+
+int la_ProcessTextEdit(laEvent *e, laStringEdit *se, laUiItem* ui){
+    int Select=e->SpecialKeyBit&LA_KEY_SHIFT;
+    int _L, MonoWidth;
+    switch (e->Type){
+    case LA_INPUT:
+        switch (e->Input){
+        case 0x08: if(strHasSelection(se)) strClearSelection(se); else strBackspace(se); return 1;
+        case 0x7f: if(strHasSelection(se)) strClearSelection(se); else { strMoveCursor(se,0,0); strBackspace(se); } return 1;
+        case 0x09: strInsertChar(se, ' ');strInsertChar(se, ' ');strInsertChar(se, ' ');strInsertChar(se, ' '); return 1;
+        case 0x1B: case 0x0D: return 0;
+        default: strInsertChar(se, e->Input); return 1;
+        }
+        break;
+    case LA_KEY_DOWN:
+        switch (e->key){
+        case LA_KEY_ENTER: strInsertChar(se, '\n'); return 1;
+        case LA_KEY_ARRLEFT: strMoveCursor(se, 1, Select); return 1;
+        case LA_KEY_ARRRIGHT: strMoveCursor(se, 0, Select); return 1;
+        case LA_KEY_ARRUP: strMoveCursorLine(se, 1, Select); return 1;
+        case LA_KEY_ARRDOWN: strMoveCursorLine(se, 0, Select); return 1;
+        }
+        break;
+    case LA_MOUSE_WHEEL_DOWN: strMoveView(se, MAIN.ScrollingSpeed, 0); return 1;
+    case LA_MOUSE_WHEEL_UP: strMoveView(se, -MAIN.ScrollingSpeed, 0); return 1;
+    case LA_L_MOUSE_DOWN:
+    case LA_MOUSEMOVE:
+        if(!ui) return 0;
+        MonoWidth=tnsGetMonoFontAdvance(); _L=(*ui->Type->Theme)->LM;
+        int Count=se->TotalLines; while(Count){ Count/=10; _L+=MonoWidth; }
+        if(e->Type==LA_L_MOUSE_DOWN){
+            strSetCursor(se, (e->y-ui->U)/LA_RH+se->ViewStartLine, (e->x-_L-MonoWidth/2)/MonoWidth); strCancelSelect(se); strLazySelect(se);
+            se->MouseSelecting=1; se->CursorPreferBefore=se->CursorBefore; return 1;
+        }else{
+            if(!se->MouseSelecting) return 0;
+            MonoWidth=tnsGetMonoFontAdvance(); _L=(*ui->Type->Theme)->LM;
+            int Count=se->TotalLines; while(Count){ Count/=10; _L+=MonoWidth; }
+            strSetCursor(se, (e->y-ui->U)/LA_RH+se->ViewStartLine, (e->x-_L-MonoWidth/2)/MonoWidth); strEndSelect(se);
+            se->CursorPreferBefore=se->CursorBefore; return 1;
+        }return 0;
+    case LA_L_MOUSE_UP:
+        se->MouseSelecting=0;
+    }
+    return 0;
+}
+
+int OPINV_UiItem(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    a->CustomData = ui->Extra;
+    return LA_RUNNING;
+}
+int OPINV_Tab(laOperator *a, laEvent *e){
+    laUiList *uil;
+    laUiItem *ui = a->Instance;
+    laGeneralUiExtraData *uit;
+    int count = 0;
+
+    //if (e->Type == LA_L_MOUSE_DOWN) {
+    //}
+
+    a->CustomData = ui->Extra;
+
+    uit = a->CustomData;
+    uit->TargetIndexVali = count;
+
+    return LA_RUNNING;
+}
+
+int OPEXT_UiItem(laOperator *a, int ExitCode){
+    laUiItem *ui = a->Instance;
+    return 0;
+}
+
+int OPMOD_IntArrayHorizon(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laIntProp *ip = ui->PP.LastPs->p;
+    int Away = 0;
+    int TmpArr[32];
+    int Len = laGetArrayLength(&ui->PP);
+    int IsVertical=(ui->Flags&LA_UI_FLAGS_TRANSPOSE)!=0;
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
+
+    if (!laIsInUiItem(ui, e->x, e->y) && !ui->Extra->On){
+        ui->State = LA_UI_NORMAL;
+        if (ui->Extra) ui->Extra->On = 0;
+        laRedrawCurrentPanel();
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_TIME_IDLE && !uit->On && !uit->Edit){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        if (laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING_PASS;
+        if (uit->Edit){
+            if (!laIsInUiItem(ui, e->x, e->y)){
+                strEndEdit(&uit->Edit, 1);
+                uit->On = 0;
+                laRedrawCurrentPanel();
+                return LA_FINISHED;
+            }
+            if (strHasSelection(uit->Edit)) strDeselectAll(uit->Edit);
+            else strSelectLineAll(uit->Edit);
+            return LA_RUNNING;
+        }
+        uit->LastX = e->x;
+        uit->LastY = e->y;
+        ui->Extra->On = (IsVertical ? la_DetectRow(ui, e->y) : la_DetectColumn(ui, e->x, Len)) + 1;
+        if (ui->Extra->On > Len) return LA_RUNNING;
+        laGetIntArray(&ui->PP, &TmpArr);
+        uit->TargetIndexVali = TmpArr[ui->Extra->On - 1];
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+    if (e->Type == LA_MOUSEMOVE && ui->Extra->On){
+        if(ui->Extra->Edit){ return LA_RUNNING; }
+        int dist=abs(e->x - uit->LastX);
+        if (dist > MAIN.ValuatorThreshold){
+            laGetIntArray(&ui->PP, &TmpArr);
+            uit->TargetIndexVali = TmpArr[ui->Extra->On - 1];
+            uit->TargetIndexVali += ((e->x - uit->LastX) > 0 ? 1 : -1) * ip->Step;
+            laSetIntArraySingle(&ui->PP, ui->Extra->On - 1, uit->TargetIndexVali);
+            uit->LastX = e->x;
+            uit->LastY = e->y;
+            uit->Dragging = 1;
+            laRedrawCurrentPanel();
+        }
+        return LA_RUNNING;
+    }
+    if (e->Type == LA_L_MOUSE_UP){
+        if (laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING_PASS;
+        if (uit->Dragging){
+            if (ui->Extra->On){
+                ui->Extra->On = 0;
+                laConfirmInt(a, uit->TargetIndexVali, LA_CONFIRM_DATA);
+                laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            }
+        }else if(ui->Extra->On){
+            int SelectOn=(IsVertical ? la_DetectRow(ui, e->y) : la_DetectColumn(ui, e->x, Len)) + 1; 
+            if ((!uit->Edit) || (uit->Edit && (SelectOn != ui->Extra->On))){
+                char buf[32] = {0};
+                uit->On=SelectOn;
+                laGetIntArray(&ui->PP, &TmpArr);
+                uit->TargetIndexVali = TmpArr[ui->Extra->On - 1];
+                strPrintIntAfter(buf, 32, uit->TargetIndexVali);
+                strBeginEdit(&uit->Edit,buf);
+                strSelectLineAll(uit->Edit);
+            }
+        }
+        uit->Dragging = 0;
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if(e->Type ==LA_KEY_DOWN){
+        if (e->key == LA_KEY_ENTER && uit->Edit){
+            char* buf=strEndEdit(&uit->Edit, 0);
+            int Result; sscanf(buf, "%d", &Result); free(buf);
+            laSetIntArraySingle(&ui->PP, ui->Extra->On - 1, Result);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            ui->State = LA_UI_NORMAL;
+            uit->Dragging = 0;
+            uit->On = 0;
+            laRedrawCurrentPanel();
+            return LA_FINISHED_PASS;
+        }
+    }
+    
+    if (uit->Edit){
+        if (la_ProcessTextEdit(e, uit->Edit, ui)){
+            laRedrawCurrentPanel();
+            return LA_RUNNING;
+        }
+    }
+
+    if (e->Type == LA_R_MOUSE_DOWN){
+        int GX = e->x, GY = e->y;
+        ui->PP.LastIndex = la_DetectColumn(ui, e->x, Len);
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnablePropertyPanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_FloatArrayHorizon(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laFloatProp *fp = ui->PP.LastPs->p;
+    int Away = 0;
+    real TmpArr[32];
+    int Len = laGetArrayLength(&ui->PP);
+    int IsVertical=(ui->Flags&LA_UI_FLAGS_TRANSPOSE)!=0;
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
+
+    if (!laIsInUiItem(ui, e->x, e->y) && !ui->Extra->On){
+        ui->State = LA_UI_NORMAL;
+        ui->Extra->On = 0;
+        laRedrawCurrentPanel();
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_TIME_IDLE && !uit->On && !uit->Edit){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        if (uit->Edit){
+            if (!laIsInUiItem(ui, e->x, e->y)){
+                strEndEdit(&uit->Edit, 1);
+                uit->On = 0;
+                laRedrawCurrentPanel();
+                return LA_FINISHED;
+            }
+            if (strHasSelection(uit->Edit)) strDeselectAll(uit->Edit);
+            else strSelectLineAll(uit->Edit);
+            return LA_RUNNING;
+        }
+        if (laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING_PASS;
+        uit->LastX = e->x;
+        uit->LastY = e->y;
+        ui->Extra->On = (IsVertical ? la_DetectRow(ui, e->y) : la_DetectColumn(ui, e->x, Len)) + 1;
+        if (ui->Extra->On > Len) return LA_RUNNING;
+        laGetFloatArray(&ui->PP, &TmpArr);
+        uit->TargetIndexValf = TmpArr[ui->Extra->On - 1];
+        laRedrawCurrentPanel();
+
+        return LA_RUNNING;
+    }
+    if (e->Type == LA_MOUSEMOVE && ui->Extra->On){
+        if(uit->Edit){ return LA_RUNNING; }
+        int dist=abs(e->x - uit->LastX);
+        if (dist > MAIN.ValuatorThreshold){
+            laGetIntArray(&ui->PP, &TmpArr);
+            uit->TargetIndexVali = TmpArr[ui->Extra->On - 1];
+            uit->TargetIndexValf += ((e->x - uit->LastX) > 0 ? 1 : -1) * fp->Step;
+            laSetFloatArraySingle(&ui->PP, ui->Extra->On - 1, uit->TargetIndexValf);
+            uit->LastX = e->x;
+            uit->LastY = e->y;
+            uit->Dragging = 1;
+            laRedrawCurrentPanel();
+        }
+        return LA_RUNNING;
+    }
+    if (e->Type == LA_L_MOUSE_UP){
+        if (laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING_PASS;
+        if (uit->Dragging){
+            if (ui->Extra->On){
+                ui->Extra->On = 0;
+                laConfirmFloat(a, uit->TargetIndexValf, LA_CONFIRM_DATA);
+                laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            }
+        }else if(ui->Extra->On){
+            int SelectOn=(IsVertical ? la_DetectRow(ui, e->y) : la_DetectColumn(ui, e->x, Len)) + 1; 
+            if ((!uit->Edit) || (uit->Edit && (SelectOn != ui->Extra->On))){
+                char buf[32] = {0};
+                uit->On=SelectOn;
+                laGetFloatArray(&ui->PP, &TmpArr);
+                uit->TargetIndexValf = TmpArr[ui->Extra->On - 1];
+                strPrintFloatAfter(buf, 32, 5, uit->TargetIndexValf);
+                strBeginEdit(&uit->Edit,buf);
+                strSelectLineAll(uit->Edit);
+            }
+        }
+        uit->Dragging = 0;
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if(e->Type ==LA_KEY_DOWN){
+        if (e->key == LA_KEY_ENTER && uit->Edit){
+            char* buf=strEndEdit(&uit->Edit, 0);
+            real Result; sscanf(buf, "%lf", &Result); free(buf);
+            laSetFloatArraySingle(&ui->PP, ui->Extra->On - 1, Result);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            uit->Dragging = 0;
+            uit->On = 0;
+            laRedrawCurrentPanel();
+            return LA_FINISHED_PASS;
+        }
+    }
+
+    if (uit->Edit){
+        if (la_ProcessTextEdit(e, uit->Edit, ui)){
+            laRedrawCurrentPanel();
+            return LA_RUNNING;
+        }
+    }
+
+    if (e->Type == LA_R_MOUSE_DOWN){
+        int GX = e->x, GY = e->y;
+        ui->PP.LastIndex = la_DetectColumn(ui, e->x, laGetArrayLength(&ui->PP));
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnablePropertyPanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_FloatColor(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    int Away = 0;
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
+
+    if (!laIsInUiItem(ui, e->x, e->y)){
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_TIME_IDLE){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+    
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        laUiList *uil;
+        laColumn *col;
+        laPanel *p;
+        int GX = ui->L, GY = ui->B;
+        ui->State = LA_UI_ACTIVE;
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        p = laEnableEmptyPropertyPanel(a->ToPanel, a, GX, GX + 150, GY, 500, e);{
+            uil = &p->UI;
+            col = laFirstColumn(uil);
+            laShowItemFull(uil, col, &ui->PP, 0, LA_WIDGET_FLOAT_HCY, 0, 0, 0);
+            laShowItemFull(uil, col, &ui->PP, 0, LA_WIDGET_FLOAT, 0, 0, 0)->Flags=LA_UI_FLAGS_TRANSPOSE;
+            laEnclosePanelContent(p, uil);
+        }
+        return LA_RUNNING;
+    }
+    if (e->Type == LA_R_MOUSE_DOWN){
+        int GX = e->x, GY = e->y;
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnablePropertyPanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_ColorHCY(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    int Away = 0;
+    real c = (real)((ui->R + ui->L) / 2) - LA_RH / 2; /*- bt->RM;*/
+    real r = (ui->B - ui->U - bt->TP - bt->BP) / 2;
+    int i = 0;
+    real hcy[3] = {0};
+    real Color[4] = {0};
+    real PickerPos[2];
+    real abso;
+    real dx = e->x - c, dy = e->y - (ui->U + r + bt->TP);
+    real dist = sqrt(dx * dx + dy * dy);
+
+    if (!laIsInUiItem(ui, e->x, e->y)){
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        ui->State = LA_UI_ACTIVE;
+        laRedrawCurrentPanel();
+        //return LA_RUNNING;
+    }
+    if (e->Type == LA_L_MOUSE_UP){
+        ui->State = LA_UI_NORMAL;
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if (e->Type & LA_MOUSE_EVENT && LA_UI_NORMAL != ui->State){
+        laGetFloatArray(&ui->PP, Color);
+        tnsLogToLinear(Color, MAIN.Gamma);
+        tnsRGBtoHCY(Color, hcy);
+        if (dist < r){
+            abso = fabs(atan((real)dy / (real)dx));
+            hcy[0] = abso / TNS_PI / 2;
+            if (dx > 0){
+                if (dy < 0) hcy[0] = 1 - hcy[0];
+            }else{
+                if (dy > 0){
+                    hcy[0] = 0.5 - hcy[0];
+                }else{
+                    hcy[0] += 0.5;
+                }
+            }
+            hcy[1] = dist / r;
+            //printf("hcy[1] = %d -> ",hcy[1]);
+            //if (MAIN.ColorAccessCorrectGamma) {
+            //tnsSingleLogToLinear(&hcy[1], 2.2);
+            //}
+            //printf("%d\n", hcy[1]);
+        }else if (dist < r + LA_RH * 2 && dx > 0){
+            abso = -atan((real)dy / (real)dx) / TNS_PI * 2 + 0.5;
+            hcy[2] = abso;
+            //if (MAIN.ColorAccessCorrectGamma) {
+            //    tnsSingleLogToLinear(&hcy[2], MAIN.Gamma);
+            //}
+        }
+        tnsHCYtoRGB(hcy, Color);
+        tnsLinearToLog(Color, MAIN.Gamma);
+        laSetFloatArrayAllArray(&ui->PP, Color);
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_EnumSelector(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laEnumItem *ei;
+    laEnumProp *ep = ui->PP.LastPs->p;
+    int at = 0;
+    laEnumItem *Data[32];
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
+    // norm      e1
+    // expand    e1 e2 e3
+    // expand vertical  (vertical)
+    // arr expand    e1 e1 e3
+    //               e2 e2 e3
+    // arr exp+vert  e1 e1
+    //               e2 e2
+    //               e3 e3
+
+    if (a->ConfirmData /* && a->ConfirmData->Mode == LA_CONFIRM_DATA*/){
+        ui->State = LA_UI_NORMAL;
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if (!laIsInUiItem(ui, e->x, e->y)){ return LA_FINISHED_PASS; }
+    
+    if (e->Type == LA_TIME_IDLE){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        if (laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING_PASS;
+
+        int IsVertical = ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+        int IsExpand = ui->Flags&LA_UI_FLAGS_EXPAND;
+        int IsCycle = ui->Flags&LA_UI_FLAGS_CYCLE;
+        int ArrLen = laGetArrayLength(&ui->PP);
+        if(ArrLen==1){ if(!IsExpand) IsVertical=0; }else{ IsExpand=1; }
+        int EnumLen = (IsExpand&&(!IsCycle)) ? laGetEnumEntryLen(&ui->PP) : 1;
+
+        int _L,_R,_U,_B, _W=ui->R - ui->L, _Col=1;
+        if(IsVertical){
+            if(IsExpand){ _Col=ArrLen; }
+        }else{
+            if(IsExpand){ _Col=EnumLen; } else { _Col=ArrLen; }
+        }
+
+        int row = la_DetectRow(ui, e->y);
+        int col = la_DetectColumn(ui, e->x, _Col);
+
+        int ArrTarget=0, EnumTarget=0, ShowMenu=0;
+
+        if(IsVertical){
+            if(IsExpand){ EnumTarget=row; ArrTarget=col; } else { EnumTarget=col; }
+        }else{
+            if(IsExpand){ EnumTarget=col; ArrTarget=row; } else { if(!IsCycle) ShowMenu=1; }
+        }
+
+        if(ShowMenu){
+            int GX = ui->L, GY = ui->B, GR = ui->R, t = 0;
+            ui->State = LA_UI_ACTIVE;
+            laLocalToWindow(a, a->ToPanel, &GX, &GY);
+            laLocalToWindow(a, a->ToPanel, &GR, &t);
+            laEnablePropertyPanel(a->ToPanel, a, 0, la_DefaultEnumPanel, &ui->PP, GX, GR, GY, 200, 300, e);
+            laRedrawCurrentPanel();
+        }elif(IsCycle){
+            laEnumItem* ei=laGetEnumArrayIndexed(&ui->PP, ArrTarget);
+            ei = ei->Item.pNext?ei->Item.pNext:((laEnumProp*)ui->PP.LastPs->p)->Items.pFirst;
+            laSetEnumArrayIndexed(&ui->PP, ArrTarget, ei->Index);
+            laConfirmInt(a,EnumTarget,LA_CONFIRM_DATA);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+        }else{
+            if(ArrTarget>=ArrLen){ArrTarget=ArrLen-1;} 
+            if(EnumTarget>=EnumLen){EnumTarget=EnumLen-1;}
+            laSetEnumArrayIndexedExternal(&ui->PP, ArrTarget, EnumTarget);
+            laConfirmInt(a,EnumTarget,LA_CONFIRM_DATA);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            return LA_RUNNING_PASS;
+        }
+        return LA_RUNNING;
+    }
+
+    if(e->Type==LA_R_MOUSE_DOWN){
+        int GX = e->x, GY = e->y;
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnablePropertyPanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_Button(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int lx, ly;
+    int Away = 0;
+
+    if (e->Type == LA_TIME_IDLE && !ui->State){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a,  &ui->ExtraPP, 0,  &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+    
+    if (laConfirmSameDataIfAny(a)) return LA_RUNNING_PASS;
+
+    if (e->Type == LA_ESCAPE_DOWN || e->Type == LA_INPUT) return LA_FINISHED; //debug
+
+    if (!laIsInUiItem(ui, e->x, e->y) /*&& ui->State!= LA_UI_ACTIVE*/){
+        ui->State = LA_UI_NORMAL;
+        laRedrawCurrentPanel();
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        ui->State = LA_UI_ACTIVE;
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    char *str;
+
+    if (e->Type == LA_L_MOUSE_UP && ui->State!=LA_UI_NORMAL){
+        ui->State = LA_UI_NORMAL;
+        if (ui->AT){
+            if (!ui->Instructions){
+                if (ui->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->ExtraInstructions->Ptr);
+                if (ui->AT->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->AT->ExtraInstructions);
+            }
+
+            if (!laOperatorAvailableP(ui->AT, 0, ui->Instructions)) return LA_RUNNING;
+
+            lx = e->x;
+            ly = e->y;
+            laLocalToWindow(a, a->ToPanel, &e->x, &e->y);
+            e->Localized = 0;
+            laInvokeP(0, ui->AT, e, 0, ui->ExtraInstructions ? ui->ExtraInstructions->Ptr : 0, 0);
+            e->x = lx;
+            e->y = ly;
+            e->Localized = 1;
+        }else{
+            laOperatorProp *ap = ui->PP.LastPs->p;
+            if (ap->OperatorID){
+
+                if (!ap->OperatorType) ap->OperatorType = laGetOperatorType(ap->OperatorID);
+
+                if (!ui->Instructions){
+                    if (ui->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->ExtraInstructions->Ptr);
+                    if (ap->OperatorType) strMakeInstructions(&ui->Instructions, ap->OperatorType->ExtraInstructions);
+                }
+
+                if (!laOperatorAvailablePSafe(ap->OperatorType, ui->PP.RawThis, ui->PP.Go->UseInstance, ui->Instructions)) return LA_RUNNING;
+
+                lx = e->x;
+                ly = e->y;
+                laLocalToWindow(a, a->ToPanel, &e->x, &e->y);
+                e->Localized = 0;
+                laInvokePCreateThis(0, ap->OperatorType, e, ui->PP.RawThis, ui->PP.Go->UseInstance, ui->ExtraInstructions ? ui->ExtraInstructions->Ptr : 0, ap->Base.ExtraInstructions);
+                if(a->StopNow) return LA_FINISHED;
+                laRetriggerOperators();
+                e->x = lx;
+                e->y = ly;
+                e->Localized = 1;
+            }
+        }
+
+        if (str = strGetArgumentString(ui->Instructions, "feedback")){
+            if (strSame(str, "CONFIRM")) laConfirmInt(a, 0, LA_CONFIRM_OK);
+            elif (strSame(str, "CANCEL")) laConfirmInt(a, 0, LA_CONFIRM_CANCEL);
+            else { laConfirmString(a, str, LA_CONFIRM_CUSTOM_STRING); }
+        }elif(!(ui->Flags&LA_UI_FLAGS_NO_CONFIRM)){
+            laConfirmInt(a, 0, LA_CONFIRM_OK);
+        }
+
+        laRedrawCurrentPanel();
+        return LA_RUNNING_PASS;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_MenuItem(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laPanel *p;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    int Away = 0;
+
+    if (a->ConfirmData){
+        ui->State = LA_UI_NORMAL;
+        laConfirmInt(a, a->ConfirmData->IData, a->ConfirmData->Mode);
+        laRedrawCurrentPanel();
+        return LA_RUNNING_PASS;
+    }
+
+    if (!laIsInUiItem(ui, e->x, e->y) && ui->State != LA_UI_ACTIVE){
+        ui->State = LA_UI_NORMAL;
+        laRedrawCurrentPanel();
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        int GX = ui->L, GY = ui->B;
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        ui->State = LA_UI_ACTIVE;
+        p = laEnableMenuPanel(a->ToPanel, a, ui->Subs.pFirst, &ui->PP, GX, GX + 300, GY, 600, 200, e);
+        laShowPanelWithDropDownEffect(p);
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_ConditionToggle(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    int Away = 0;
+
+    if (!laIsInUiItem(ui, e->x, e->y) /*&& ui->State!= LA_UI_ACTIVE*/){
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        ui->State = ui->State == LA_UI_ACTIVE ? LA_UI_NORMAL : LA_UI_ACTIVE;
+        laRecalcCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_SingleLineString(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laStringEdit *se = uit->Edit;
+    int Away = 0;
+    char _buf[LA_RAW_CSTR_MAX_LEN] = {0}; char* buf=_buf;
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
+
+    if (!laIsInUiItem(ui, e->x, e->y)){
+        if (ui->State != LA_UI_EDITING){
+            ui->State = LA_UI_NORMAL;
+            laRedrawCurrentPanel();
+            return LA_FINISHED_PASS;
+        }else if ((e->Type & LA_MOUSEDOWN) == LA_MOUSEDOWN){
+            buf=strEndEdit(&uit->Edit, 0);
+            laSetString(&ui->PP, buf); free(buf);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            ui->State = LA_UI_NORMAL;
+            laRedrawCurrentPanel();
+            return LA_FINISHED_PASS;
+        }
+    }
+
+    if (e->Type == LA_TIME_IDLE && !ui->State){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+    
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
+    if(e->Type ==LA_KEY_DOWN){
+        if (e->key == LA_KEY_ENTER){
+            buf=strEndEdit(&uit->Edit, 0);
+            laSetString(&ui->PP, buf); free(buf);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            ui->State = LA_UI_NORMAL;
+            laRedrawCurrentPanel();
+            return LA_FINISHED_PASS;
+        }else if (e->key == LA_KEY_ESCAPE && ui->State != LA_UI_NORMAL){
+            ui->State = LA_UI_NORMAL;
+            laRedrawCurrentPanel();
+            return LA_FINISHED;
+        }
+    }
+
+    if(laKeyMapExecuteEventEx(a, &ui->ExtraPP, &ui->Type->KeyMapper, e)) return LA_RUNNING;
+
+    if (ui->State == LA_UI_EDITING){
+        laRedrawCurrentPanel();
+        if (la_ProcessTextEdit(e, se, ui)) return LA_RUNNING;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        if (ui->State == LA_UI_NORMAL){
+            if(laIsPropertyReadOnly(&ui->PP)) return LA_RUNNING;
+            ui->State = LA_UI_EDITING;
+            laGetString(&ui->PP, _buf, &buf);
+            strBeginEdit(&uit->Edit,buf);
+            strSelectLineAll(uit->Edit);
+        }elif (ui->State == LA_UI_EDITING){
+            if (strHasSelection(uit->Edit)) strDeselectAll(uit->Edit);
+            else strSelectLineAll(uit->Edit);
+        }
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if (e->Type == LA_R_MOUSE_DOWN){
+        int GX = e->x, GY = e->y;
+        ui->PP.LastIndex = la_DetectColumn(ui, e->x, laGetArrayLength(&ui->PP));
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnablePropertyPanel(a->ToPanel, a, ui->State==LA_UI_EDITING?&ui->ExtraPP:0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if (ui->State != LA_UI_EDITING) return LA_RUNNING_PASS;
+    else
+        return LA_RUNNING;
+}
+void la_SetMultistringViewRange(laUiItem* ui, laStringEdit* se, laBoxedTheme* bt){
+    int NumberWidth=0; int MonoWidth=tnsGetMonoFontAdvance(); int Count=se->TotalLines;
+    while(Count){ Count/=10; NumberWidth+=MonoWidth; }
+    strSetEditViewRange(ui->Extra->Edit,ui->Extra->HeightCoeff,(ui->R-ui->L-NumberWidth-bt->LM*2-bt->RM)/MonoWidth);
+}
+int OPMOD_MultiString(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *es = a->CustomData;
+    laStringEdit *se = es->Edit;
+    int Away = 0;
+    char _buf[LA_RAW_CSTR_MAX_LEN] = {0}; char* buf=&_buf;
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
+
+    if (!laIsInUiItem(ui, e->x, e->y) && !es->Dragging){
+        if ((e->Type & LA_MOUSEDOWN) == LA_MOUSEDOWN){
+            buf=strGetEditString(es->Edit, 0); laSetString(&ui->PP, buf); free(buf);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            ui->State = LA_UI_NORMAL;
+            laRedrawCurrentPanel();
+            return LA_FINISHED_PASS;
+        }
+        if(ui->State!=LA_UI_ACTIVE) return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_TIME_IDLE && ui->State!=LA_UI_ACTIVE){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
+    if(e->Type ==LA_KEY_DOWN){
+        if (e->key == LA_KEY_ESCAPE){
+            if(ui->State != LA_UI_NORMAL){
+                buf=strGetEditString(es->Edit, 0); laSetString(&ui->PP, buf); free(buf);
+                laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+                ui->State = LA_UI_NORMAL; laRedrawCurrentPanel();la_SetMultistringViewRange(ui,es->Edit,bt);
+            }
+            if(es->Dragging){ es->Dragging=0; es->HeightCoeff=es->TargetIndexVali; laRecalcCurrentPanel();la_SetMultistringViewRange(ui,es->Edit,bt); }
+            return LA_FINISHED;
+        }
+    }
+
+    if(laKeyMapExecuteEventEx(a, &ui->ExtraPP, &ui->Type->KeyMapper, e)) return LA_RUNNING;
+    
+    if(e->Type == LA_L_MOUSE_DOWN && es->HeightCoeff>=0 && e->x>ui->R-bt->RM-LA_RH && e->y>ui->B-bt->BM-LA_RH){
+        es->Dragging=1; es->LastX=e->x; es->LastY=e->y; es->TargetIndexVali=es->HeightCoeff;
+        return LA_RUNNING;
+    }
+    if(es->Dragging){
+        if(e->Type==LA_MOUSEMOVE){ es->HeightCoeff=es->TargetIndexVali+((real)e->y-es->LastY+0.5)/LA_RH;
+            if(es->HeightCoeff<1)es->HeightCoeff=1; laRecalcCurrentPanel(); la_SetMultistringViewRange(ui,es->Edit,bt);}
+        elif(e->Type==LA_L_MOUSE_UP){ es->Dragging=0; }
+        elif(e->Type==LA_R_MOUSE_DOWN){
+            es->Dragging=0; es->HeightCoeff=es->TargetIndexVali; laRecalcCurrentPanel();la_SetMultistringViewRange(ui,se,bt); }
+        return LA_RUNNING;
+    }
+
+    if (ui->State == LA_UI_ACTIVE){
+        laRedrawCurrentPanel();
+        if (la_ProcessTextEdit(e, se, ui)) return LA_RUNNING;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        if (ui->State == LA_UI_NORMAL){
+            ui->State = LA_UI_ACTIVE;
+            laGetString(&ui->PP, _buf, &buf);
+            strBeginEdit(&es->Edit,buf);la_SetMultistringViewRange(ui,es->Edit,bt);
+        }
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if (e->Type == LA_R_MOUSE_DOWN){
+        int GX = e->x, GY = e->y;
+        ui->PP.LastIndex = la_DetectColumn(ui, e->x, laGetArrayLength(&ui->PP));
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnablePropertyPanel(a->ToPanel, a, ui->State==LA_UI_ACTIVE?&ui->ExtraPP:0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if (ui->State != LA_UI_ACTIVE) return LA_RUNNING_PASS;
+    else return LA_RUNNING;
+}
+int OPMOD_TabSelector(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laUiList *uil;
+    int Away = 0;
+    int count = 0;
+    int it = 0;
+    int page;
+
+    if (!laIsInUiItem(ui, e->x, e->y) || laIsInBound(e->x, e->y, ui->Page->L, ui->Page->R, ui->Page->U, ui->Page->B)){
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        if (ui->Page->HeightCoeff && ui->R - e->x < LA_RH + bt->RM) return LA_RUNNING_PASS;
+        for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){
+            count++;
+        }
+        page = la_DetectColumn(ui, e->x, count);
+        for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){
+            if (it == page){
+                laRecalcCurrentPanel();
+                ui->Page = uil;
+                return LA_RUNNING;
+            }else
+                it++;
+        }
+    }
+    
+    return LA_RUNNING_PASS;
+}
+int OPMOD_Collection(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laGeneralUiExtraData *uit = a->CustomData;
+    laListHandle Locals = {0};
+    laUiList *uil;
+    int lx = e->x, ly = e->y;
+    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;
+    }
+
+    laLocalToPanel(a, &lx, &ly); if(a->ToPanel && ly<a->ToPanel->TitleBar.B){ return LA_FINISHED_PASS; }
+    uil = la_DetectUiListRecursive(ToUil, lx, ly, 10000, 0, 0, 0, 0, 0);
+    if (uil != ((laUiListDrawItem *)a->LocalUiLists.pFirst)->Target){
+        printf("EXIT\n");
+        return LA_FINISHED;
+    }
+
+    if (e->Type & LA_MOUSE_EVENT){
+        laUiList *sub;
+        laUiItem *tui;
+        int LimHeight = 10000;
+        int UIB = ui->B, UIU = ui->U;
+        int t = 0;
+        void *Active = ui->PP.EndInstance;
+        if (ui->Subs.pFirst) LimHeight = (int)((laUiList *)ui->Subs.pFirst)->HeightCoeff;
+        if (LimHeight > 0) UIB = LimHeight;
+        laPanelToLocal(a, &t, &UIB);
+        for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){
+            ui->PP.EndInstance = sub->Instance;
+            if ((tui = la_DetectUiItemRecursive(sub, e->x, e->y, UIB, &Locals, 0))){
+                if (tui && !a->Child && tui->Type->OperatorType){
+                    //printf("invui %d\n", tui);
+                    laSetOperatorLocalizer(a->ToPanel);
+                    laInvokeUiP(a, tui->Type->OperatorType, e, tui, &Locals, 0);
+                }
+            }
+            lstClearPointer(&Locals);
+        }
+        ui->PP.EndInstance = Active;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        laUiList *uil;
+        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();
+                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);
+                laRecordAndPush(&PP,0); laMarkPropChanged(&PP);
+                laConfirmInt(a, 0, LA_CONFIRM_DATA);
+                return LA_RUNNING_PASS;
+            }
+        }
+        return LA_RUNNING;
+    }
+    elif (e->Type == LA_R_MOUSE_DOWN) {
+        laUiList* uil;
+        for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext) {
+            if (laIsInBound(e->x, e->y, uil->L, uil->R, uil->U, uil->B)) {
+                //laSetActiveInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, uil->Instance);
+                laInvoke(a, "LA_file_dialog", e, 0, 0, 0);
+                uit->Ptr1 = uil->Instance;
+                laRedrawCurrentPanel();
+                laConfirmInt(a, 0, LA_CONFIRM_DATA);
+                return LA_RUNNING;
+            }
+        }
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_CollectionSelector(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laEnumItem *ei;
+    laEnumProp *ep = ui->PP.LastPs->p;
+    int at = 0;
+
+    if (a->ConfirmData /* && a->ConfirmData->Mode == LA_CONFIRM_DATA*/){
+        ui->State = LA_UI_NORMAL;
+        laRecalcCurrentPanel();
+        return LA_RUNNING;
+    }
+
+    if (!laIsInUiItem(ui, e->x, e->y)){
+        return LA_FINISHED;
+    }
+
+    if (e->Type == LA_TIME_IDLE && !ui->State){
+        int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laPanel *p = laEnableIdlePanel(a->ToPanel, a, 0, 0, &ui->PP, GX, GX + 150, GY, 600, 200, e);
+        return LA_RUNNING;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        laUiList *uil;
+        laColumn *col;
+        laPanel *p;
+        int GX = ui->L, GY = ui->B, GR = ui->R, t = 0;
+
+        if (e->x >= TNS_MAX2(ui->R - LA_RH,(ui->R+ui->L)/2) && e->x < ui->R){
+            laSetActiveInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, 0);
+            laRecordAndPush(&ui->PP,0); laMarkPropChanged(&ui->PP);
+            return LA_FINISHED;
+        }
+
+        laLocalToWindow(a, a->ToPanel, &GX, &GY);
+        laLocalToWindow(a, a->ToPanel, &GR, &t);
+        laRedrawCurrentPanel();
+        ui->State = LA_UI_ACTIVE;
+        p = laEnableEmptyPropertyPanel(a->ToPanel, a, GX, GR, GY, 500, e);{
+            int MinWidth;
+            uil = &p->UI;
+            col = laFirstColumn(uil);
+            laShowItemFull(uil, col, &ui->PP, 0, LA_WIDGET_COLLECTION, 0, ui->Template, 0)->SymbolID = ui->SymbolID;
+            laEnclosePanelContent(p, &p->UI);
+        }
+        return LA_RUNNING;
+    }
+    return LA_RUNNING_PASS;
+}
+int OPMOD_ColumnAdjuster(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    laColumn *c = uit->Ptr1;
+
+    c = uit->Ptr1 ? uit->Ptr1 : la_DetectSplit(ui->C, e->x);
+    if ((!uit->Dragging) && (!laIsInUiItem(ui, e->x, e->y)||!c)){
+        printf("done\n");
+        return LA_FINISHED_PASS;
+    }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        uit->Ptr1 = c;
+        uit->LastX = e->x;
+        uit->Dragging=1;
+        return LA_RUNNING;
+    }
+    if (uit->Dragging && uit->Ptr1 && e->Type == LA_MOUSEMOVE){
+        la_AdjustColumnSplit(c, e->x - uit->LastX);
+        uit->LastX = e->x;
+        laRecalcCurrentPanel();
+        return LA_RUNNING;
+    }
+    if (uit->Dragging && (e->Type == LA_L_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN || e->key == LA_KEY_ESCAPE)){
+        uit->Ptr1 = 0; uit->Dragging=0;
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING;
+}
+int OPMOD_NodeSocket(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    int lx=e->x,ly=e->y;
+
+    laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0);
+    laPropContainer* PCFind;
+    if(pc==LA_PC_SOCKET_IN)   { PCFind=LA_PC_SOCKET_OUT; }
+    elif(pc==LA_PC_SOCKET_OUT){ PCFind=LA_PC_SOCKET_IN; }
+
+    if ((!uit->Dragging) && (!laIsInUiItem(ui, e->x, e->y))){ return LA_FINISHED_PASS; }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        uit->Dragging=1; MAIN.NextWireColor+=3;
+        if(pc==LA_PC_SOCKET_IN)   {
+            laNodeInSocket* s=ui->PP.EndInstance;
+            uit->Ptr2 = s->Source;
+            if(!s->Source){
+                s->ColorId=MAIN.NextWireColor; s->Source=&MAIN.tNodeOut;
+                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;
+            }
+        }
+        elif(pc==LA_PC_SOCKET_OUT){ MAIN.tNodeIn.Source=ui->PP.EndInstance;
+            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;
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+    if (uit->Dragging && e->Type == LA_MOUSEMOVE){
+        laPanel* p=MAIN.CurrentPanel;
+        laLocalToPanel(a, &lx, &ly);
+        laUiItem* tui=la_DetectSocketRecursive(&p->UI,lx,ly,100000,uit->Ptr2?LA_PC_SOCKET_IN:PCFind); uit->Ptr1=tui;
+        if(pc==LA_PC_SOCKET_IN){
+            if(!uit->Ptr2){MAIN.tNodeOut.RuntimeX=e->x-uit->LastX;MAIN.tNodeOut.RuntimeY=e->y-uit->LastY;}
+            else { MAIN.tNodeIn.RuntimeX=e->x-uit->LastX;MAIN.tNodeIn.RuntimeY=e->y-uit->LastY; } }
+        elif(pc==LA_PC_SOCKET_OUT){ MAIN.tNodeIn.RuntimeX=e->x-uit->LastX; MAIN.tNodeIn.RuntimeY=e->y-uit->LastY; }
+        laRedrawCurrentPanel();
+        return LA_RUNNING;
+    }
+    if (uit->Dragging && (e->Type == LA_L_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN || e->key == LA_KEY_ESCAPE)){
+        uit->Dragging=0; MAIN.tNodeIn.Source=0;
+        laRecalcCurrentPanel();
+        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);
+                s->ColorId=MAIN.NextWireColor; laRecordAndPush(&ui->PP, 0); laMarkPropChanged(&ui->PP);
+            }else{
+                if(!tui){
+                    laNodeInSocket* s=ui->PP.EndInstance; s->Source=uit->Ptr2; memAssignRef(s,&s->Source,0);
+                    laRecordAndPush(&ui->PP, 0); laMarkPropChanged(&ui->PP);
+                }else{
+                    laNodeInSocket* s=soc; if(s->Source){ uit->Ptr2=0; return LA_RUNNING; }
+                    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);
+                }
+            }
+        }
+        else{
+            if(!tui){ return LA_RUNNING; }
+            laNodeInSocket* s=soc; s->Source=0; memAssignRef(s,&s->Source,ui->PP.EndInstance);
+            s->ColorId=MAIN.NextWireColor; laRecordAndPush(&tui->PP, 0); laMarkPropChanged(&tui->PP);
+        }
+        
+        uit->Ptr2=0;
+        return LA_RUNNING;
+    }
+
+    return LA_RUNNING_PASS;
+}
+int OPMOD_HeightAdjuster(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laGeneralUiExtraData *uit = a->CustomData;
+    int lx=e->x,ly=e->y;
+    int ClickedVal=0;
+
+    if ((!uit->Dragging) && (!laIsInUiItem(ui, e->x, e->y))){ return LA_FINISHED_PASS; }
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        uit->Dragging=1; uit->LastY=e->y; uit->On=0;
+        return LA_RUNNING;
+    }
+    if (uit->Dragging && e->Type == LA_MOUSEMOVE){
+        int diff=e->y-uit->LastY; diff=((real)diff+0.5)/(ui->B-ui->U);
+        if(diff!=uit->On){ int d=diff-uit->On; uit->On=diff; while(d){ laSetInt(&ui->PP, d>0?1:-1); d-=(d>0?1:-1); }; laRecalcCurrentPanel(); }
+        return LA_RUNNING;
+    }
+    if (uit->Dragging && (e->Type == LA_L_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN || e->key == LA_KEY_ESCAPE)){
+        uit->Dragging=0; return LA_RUNNING_PASS;
+    }
+
+    return LA_RUNNING_PASS;
+}
+
+void la_RegisterUiOperatorsBasic(){
+    laPropContainer *pc, *p;
+    laOperatorType *at;
+    laEnumProp *ep;
+
+    laCreateOperatorType("LA_edit_string_copy", "Copy Selection", "Copy selected string to clip board",
+                          OPCHK_EditStringCopySelection, 0, 0, OPINV_EditStringCopySelection, 0, L'🗍', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+
+    laCreateOperatorType("LA_int_array_h_operator", "Int(Horizon) UiItem Operator", "Do Array Valuator Stuff",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_IntArrayHorizon, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_real_array_h_operator", "Float(Horizon) UiItem Operator", "Do Array Valuator Stuff",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_FloatArrayHorizon, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_real_color_operator", "Color(Float) Display UiItem Operator", "Color Display,Click To Set Color",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_FloatColor, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_real_hcy_operator", "HCY Color Picker UiItem Operator", "HCY Color Picker,Click To Set Color",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_ColorHCY, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_enum_selector_operator", "Enum Selector UiItem Operator", "Do Selector Stuff",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_EnumSelector, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_button_operator", "Button UiItem Operator", "Execute an Operator",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_Button, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_menu_root_operator", "Menu Root UiItem Operator", "Drop A Menu",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_MenuItem, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_condition_toggle_operator", "Condition +/- Button Operator", "Do Self Condition Function",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_ConditionToggle, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_string_operator", "Single Line String Operator", "Do String Modifying Function",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_SingleLineString, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_string_multi", "Multi Line String Operator", "Do String Modifying Function",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_MultiString, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_tab_operator", "Tab Switcher Operator", "Change The Page In The Tab Group",
+                          0, 0, OPEXT_UiItem, OPINV_Tab, OPMOD_TabSelector, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_collection_operator", "Collection UiItem Operator", "Activate/Deactivate Collection Item(s)",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_Collection, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_collection_selector_operator", "Collection Dropdown Selector Operator", "Do Selector Stuff",
+                          0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_CollectionSelector, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_column_adjuster", "Column Width Adjuster", "Drag To Set Width of Columns",
+                        0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_ColumnAdjuster, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_node_socket", "Node Socket Operator", "Drag to connect node sockets",
+                        0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_NodeSocket, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+    laCreateOperatorType("LA_height_adjuster", "Height Adjuster Operator", "Drag to adjust heights of an instance",
+                        0, 0, OPEXT_UiItem, OPINV_UiItem, OPMOD_HeightAdjuster, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+}
+

+ 993 - 0
source/lagui/resources/la_widgets_viewers.c

@@ -0,0 +1,993 @@
+#include "../la_5.h"
+
+extern LA MAIN;
+extern struct _tnsMain *T;
+
+//============================================================= [Draw]
+
+extern tnsFontManager *FM;
+
+
+void la_RootObjectDrawFullscreenQuad(tnsCamera* c, real Aspect){
+    real FOV = c->FOV;
+    tnsMatrix44d mat;
+    tnsGetMVMatrix(mat);
+    real vv[3]={0,0,-1};
+    real ViewDir[3]={0},vdTR[3]={0},vdBR[3]={0},vdTL[3]={0},vdBL[3]={0};
+    tnsApplyRotation43d(ViewDir,mat,vv);
+    real fovv=FOV/2, fovh=fovh=atan(tan(FOV/2)*Aspect);
+    vv[0]=tan(fovh); vv[1]=tan(fovv); tnsApplyRotation43d(vdTR,mat,vv); // note don't normalize those.
+    vv[0]=tan(fovh); vv[1]=tan(-fovv);tnsApplyRotation43d(vdBR,mat,vv);
+    vv[0]=tan(-fovh);vv[1]=tan(-fovv);tnsApplyRotation43d(vdBL,mat,vv);
+    vv[0]=tan(-fovh);vv[1]=tan(fovv); tnsApplyRotation43d(vdTL,mat,vv);
+    tnsUseRayShader();
+    tnsEnableShaderv(T->RayShader);
+    real uv[12]; tnsMakeQuad3d(uv, LA_COLOR3(vdTL), LA_COLOR3(vdTR), LA_COLOR3(vdBR), LA_COLOR3(vdBL));
+    real vt[8]; tnsMakeQuad2d(vt, -1,1, 1,1, 1,-1, -1,-1);
+    tnsTexCoordArray3d(uv,4);
+    tnsVertexArray2d(vt,4);
+    tnsPackAs(GL_TRIANGLE_FAN);
+    glUniform3f(T->RayShader->uViewDir,LA_COLOR3(ViewDir));
+    glUniform3f(T->RayShader->uViewPos,LA_COLOR3(c->Base.Location));
+    glUniform1f(T->RayShader->uFOV,FOV);
+    tnsFlush();
+    tnsUseImmShader();
+}
+
+#define LA_DEPTH_RESOLUTION 1024
+
+void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
+    laCanvasExtra *e = ui->Extra;
+    tnsCamera *c = e->UsingCamera ? e->UsingCamera : e->ViewingCamera;
+    int W, H;
+    W = ui->R - ui->L;
+    H = ui->B - ui->U;
+
+    tnsFlush();
+
+    if (!W || !H) return;
+
+    if (!e->OffScr || e->OffScr->pColor[0]->Height != ui->B - ui->U || e->OffScr->pColor[0]->Width != ui->R - ui->L){
+        if (e->OffScr) tnsDelete2DOffscreen(e->OffScr);
+        e->OffScr = tnsCreate2DOffscreen(GL_RGBA, W, H, MAIN.PanelMultisample ,1);
+    }
+
+    if (0){//(e->CurrentScene && e->CurrentScene->ActiveSun){
+        //if(!e->OffScrShadow) e->OffScrShadow = tnsCreate2DOffscreen(0, LA_DEPTH_RESOLUTION, LA_DEPTH_RESOLUTION, MAIN.PanelMultisample, 1);
+
+        //tnsUseNoTexture();
+        //tnsDrawToOffscreen(e->OffScrShadow, 1, TNS_ATTACHMENT_ARRAY_NONE);
+        //tnsViewportWithScissor(0,0,LA_DEPTH_RESOLUTION,LA_DEPTH_RESOLUTION);
+        //glEnable(GL_DEPTH_TEST);
+        //glClearDepth(1.0); glClear(GL_DEPTH_BUFFER_BIT);
+        //tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
+        //tnsEnableShaderv(T->ShadowShader);
+        //tnsUseShadowShader();
+        //tnsApplyShadowCameraView(e->CurrentScene->ActiveSun);
+        //
+        //real p[12];
+        //tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        //tnsMakeQuad3d(p, -100,-100, 25,-100,100, 25,100,100, 25,100,-100, 25);
+        //tnsVertexArray3d(p, 4); tnsPackAs(GL_TRIANGLE_FAN);
+        //tnsMakeQuad3d(p, -100,-100, 74,-100,100, 74,100,100, 74,100,-100, 74);
+        //tnsVertexArray3d(p, 4); tnsPackAs(GL_TRIANGLE_FAN);
+        ////tnsDrawFloor(e->GridSize, e->GridSpan, e->ShowAxis);
+        //tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        //tnsDrawFloor(e->GridSize, e->GridSpan, e->ShowAxis);
+        //tnsEnableShaderv(T->immShader);
+        //tnsFlush();
+
+        tnsDrawToOffscreen(e->OffScr,1,0);
+
+        tnsViewportWithScissor(0, 0, W, H);
+        tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL));
+        tnsClearAll();
+
+        //tnsUseSceneShader();
+        //tnsEnableShaderv(T->SceneShader);
+        //tnsApplyShadowCameraView(e->CurrentScene->ActiveSun);
+        tnsApplyCameraView(W, H, c);
+//
+        //tnsUseTexture(e->OffScrShadow->pDepth);
+//
+        //tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        //tnsMakeQuad3d(p, -100,-100, 25,-100,100, 25,100,100, 25,100,-100, 25);
+        //tnsVertexArray3d(p, 4); tnsPackAs(GL_TRIANGLE_FAN);
+        //tnsMakeQuad3d(p, -100,-100, 74,-100,100, 74,100,100, 74,100,-100, 74);
+        //tnsVertexArray3d(p, 4); tnsPackAs(GL_TRIANGLE_FAN);
+
+        //tnsUseNoTexture();
+        //if (!e->LineDrawingMode && e->ShowFloorGrid){
+        //    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        //    tnsDrawFloor(e->GridSize, e->GridSpan, e->ShowAxis);
+        //    tnsFlush();
+        //}
+//
+        //tnsFlush();
+
+    }else if(e->OffScrShadow){ tnsDelete2DOffscreen(e->OffScrShadow); }
+
+
+    //{
+    //    tnsDrawToOffscreen(e->OffScr, 1, 0);
+    //    //tnsUseShader(T->TEST_MatcapShader);
+    //    tnsEnableShaderv(T->TEST_MatcapShader);
+    //    tnsViewportWithScissor(0, 0, W, H);
+    //    tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL));
+    //    tnsClearAll();
+    //}
+
+    tnsDrawToOffscreen(e->OffScr,1,0);
+    tnsViewportWithScissor(0, 0, W, H);
+    tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL));
+    tnsClearAll();
+
+    tnsApplyCameraView(W, H, c);
+    tnsPushMatrix();
+    tnsPopMatrix(); //those are necessary when ui is the first in list;
+
+    //glEnable(GL_DEPTH_TEST);
+        
+    tnsEnableShaderv(T->immShader);
+    tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
+    glPointSize(6); glLineWidth(3);
+    tnsDrawObjectTree(root, 0, 0);
+    glPointSize(1); glLineWidth(10);
+
+    glDepthMask(GL_FALSE); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); //glEnable(GL_POLYGON_OFFSET_LINE); glPolygonOffset(1,1);
+    tnsDrawObjectTree(root, e->ActiveObject, 1);
+    glDepthMask(GL_TRUE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+    glLineWidth(1);
+
+    tnsUseImmShader();
+
+    //laInvoke(0,"M_select",e,&ui->ExtraPP,0,0);
+
+    //glColorMask(GL_FALSE, GL_FALSE,GL_FALSE,GL_FALSE);
+    //tnsDrawObjectTree(e->CurrentScene, 0);
+
+    tnsFlush();
+    //glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+
+    if (!e->LineDrawingMode && e->ShowFloorGrid){
+        tnsUseNoTexture();
+        real* color=laThemeColor(bt,LA_BT_BORDER); tnsColor4d(LA_COLOR3(color),0.4);
+        tnsDrawFloor(e->GridSize, e->GridSpan, e->ShowAxis);
+        tnsFlush();
+    }
+
+    //glDisable(GL_DEPTH_TEST);
+
+    //la_RootObjectDrawFullscreenQuad(c, (real)W/(real)H);
+}
+void la_RootObjectDrawOverlay(laUiItem *ui, int h){
+    laCanvasExtra *e = ui->Extra;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+
+    tnsDraw2DTextureDirectly(e->OffScr->pColor[0], ui->L, ui->U, ui->R - ui->L, ui->B - ui->U);
+
+    //if(e->OffScrShadow){
+        //tnsDraw2DTextureDirectly(e->OffScrShadow->pDepth, ui->L, ui->U, ui->R - ui->L, ui->B - ui->U);
+    //}
+
+    tnsUseNoTexture();
+
+    if (e->DrawCursor){
+        if(e->DrawCursor==LA_CANVAS_CURSOR_ARROW){
+            tnsColor4dv(laThemeColor(bt,LA_BT_TEXT));
+            tnsVertex2d(e->OnX, e->OnY); tnsVertex2d(e->TargetX, e->TargetY);
+            tnsPackAs(GL_LINES);
+        }else{
+            if(e->DrawCursor==LA_CANVAS_CURSOR_BOX){
+                tnsColor4dv(laAccentColor(LA_BT_NORMAL));
+                tnsVertex2d(e->ClickedX, e->ClickedY); tnsVertex2d(e->ClickedX, e->OnY);
+                tnsVertex2d(e->OnX, e->OnY); tnsVertex2d(e->OnX, e->ClickedY);
+                tnsPackAs(GL_TRIANGLE_FAN);
+                tnsColor4dv(laAccentColor(LA_BT_TEXT));
+                tnsVertex2d(e->ClickedX, e->ClickedY); tnsVertex2d(e->ClickedX, e->OnY);
+                tnsVertex2d(e->OnX, e->OnY); tnsVertex2d(e->OnX, e->ClickedY);
+                tnsPackAs(GL_LINE_LOOP);
+            }
+            tnsColor4dv(laThemeColor(bt,LA_BT_TEXT));
+            tnsVertex2d(e->OnX, ui->U); tnsVertex2d(e->OnX, ui->B);
+            tnsVertex2d(ui->L, e->OnY); tnsVertex2d(ui->R, e->OnY);
+            tnsPackAs(GL_LINES);
+        }
+    }
+
+    if(MAIN.CurrentWindow->MaximizedUi!=ui){
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    tnsFlush();
+
+    char* MaxIco=(MAIN.CurrentWindow->MaximizedUi!=ui)?"🡹":"🡻";
+    tnsVector4d color; tnsVectorCopy4d(laThemeColor(bt,LA_BT_TEXT),color);
+    color[3]=ui->State==LA_UI_NORMAL?0.0:(ui->State==LA_UI_ACTIVE?0.5:1.0);
+    int startx=(ui->R+ui->L)/2-LA_RH2*2;
+    
+    tnsDrawStringAuto("☰",color,startx, startx+LA_RH, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+    tnsDrawStringAuto(MaxIco,color,startx+LA_RH, startx+LA_2RH, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+
+    if(ui->Expand>=0 && ui!=MAIN.CurrentWindow->MaximizedUi)
+        tnsDrawStringAuto("◿",laThemeColor(bt,LA_BT_BORDER),ui->R-LA_RH, ui->R, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+}
+
+void la_CanvasDrawTexture(laBoxedTheme *bt, tnsTexture *t, laUiItem* ui){
+    laCanvasExtra* e=ui->Extra;
+    int W, H; W = ui->R - ui->L; H = ui->B - ui->U;
+    if (W<=0 || H<=0) return;
+
+    tnsFlush();
+
+    if (!e->OffScr || e->OffScr->pColor[0]->Height != ui->B - ui->U || e->OffScr->pColor[0]->Width != ui->R - ui->L){
+        if (e->OffScr) tnsDelete2DOffscreen(e->OffScr);
+        e->OffScr = tnsCreate2DOffscreen(GL_RGBA, W, H, MAIN.PanelMultisample, 1);
+    }
+
+    tnsDrawToOffscreen(e->OffScr, 1, 0);
+    tnsViewportWithScissor(0, 0, W, H);
+    tnsResetViewMatrix();tnsResetModelMatrix();tnsResetProjectionMatrix();
+    tnsOrtho(e->PanX - W * e->ZoomX / 2, e->PanX + W * e->ZoomX / 2, e->PanY - e->ZoomY * H / 2, e->PanY + e->ZoomY * H / 2, 100, -100);
+
+    //glClearColor(0.3,0.3,0.3, 1);
+    if (e->ClearBackground){ tnsClearColorv(laThemeColor(bt,LA_BT_NORMAL)); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); }
+
+    // above is basic routine setup
+
+    real V[8] = {0};
+    real UV[8] = {0};
+
+    if (t){
+        real w2=t->Width/2, h2=t->Height/2;
+        tnsDraw2DTextureDirectly(t, -w2, h2, t->Width, -t->Height);
+        tnsFlush();
+
+        if (e->ImageDrawBorder){
+            tnsUseNoTexture();
+            tnsMakeQuad2d(V, -w2, -h2, -w2, h2, w2, h2, w2, -h2);
+            tnsVertexArray2d(V, 4);
+            tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+            tnsVertexArray2d(V, 4);
+            tnsPackAs(GL_LINE_LOOP);
+            tnsFlush();
+        }
+    }
+}
+real la_CanvasDrawGetDisplayStep(real Max, real Min, int AreaSize){
+    real r;
+    real Step = 1.0;
+    real DispW;
+    real Div[3] = {2.0, 2.5, 2.0};
+    int Times = 302;
+
+    while (1){
+        Times++;
+        r = tnsGetRatiod(0, Max - Min, Step);
+        DispW = tnsLinearItp(0, AreaSize, r);
+        if (DispW > 100){
+            Step /= Div[Times % 3];
+        }elif (DispW < 40){
+            Step *= Div[Times % 3];
+        }else break;
+    }
+    return Step;
+}
+void la_CanvasDrawGridW(real Ratio, int RealW, real Min, real Max, real U, real B){
+    real t;
+    real Step = la_CanvasDrawGetDisplayStep(Max, Min, RealW);
+
+    t = (real)((int)(Min / Step)) * Step;
+    for (t; t <= Max; t += Step){
+        tnsVertex2d(t, U);
+        tnsVertex2d(t, B);
+        tnsPackAs(GL_LINES);
+    }
+}
+void la_CanvasDrawGridH(real Ratio, int RealH, real Min, real Max, real L, real R){
+    real t;
+    real Step = la_CanvasDrawGetDisplayStep(Max, Min, RealH);
+
+    t = (real)((int)(Min / Step)) * Step;
+    for (t; t <= Max; t += Step){
+        tnsVertex2d(L, t);
+        tnsVertex2d(R, t);
+        tnsPackAs(GL_LINES);
+    }
+}
+void la_CanvasDrawRulerW(real Ratio, laBoxedTheme *bt, int RealW, real Min, real Max, int B){
+    char buf[20] = {0};
+    real t, IL;
+    real Step = la_CanvasDrawGetDisplayStep(Max, Min, RealW);
+    int U = B - LA_RH;
+
+    tnsUseNoTexture();
+    tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+    tnsVertex2d(0, U);
+    tnsVertex2d(RealW, U);
+    tnsVertex2d(RealW, B);
+    tnsVertex2d(0, B);
+    tnsPackAs(GL_TRIANGLE_FAN);
+    tnsColor4dv(laThemeColor(bt,LA_BT_TEXT_ACTIVE));
+    tnsVertex2d(0, U + 0.5);
+    tnsVertex2d(RealW, U + 0.5);
+    tnsPackAs(GL_LINES);
+
+    t = (real)((int)(Min / Step)) * Step;
+    for (t; t <= Max; t += Step){
+        IL = tnsGetRatiod(Min, Max, t) * (RealW);
+        sprintf(buf, "%.0f", t);
+        tnsDrawStringAuto(buf, bt->Active, IL, IL + 100, U, 0);
+    }
+}
+void la_CanvasDrawRulerRWithBkg(real Ratio, laBoxedTheme *bt, int RealH, real Min, real Max, int R){
+    real t, OrigT;
+    char buf[50][20] = {0};
+    real IL[50];
+    int i = 0;
+    int W = 0, MaxW = 0;
+    int RH = LA_RH, hH = RH / 2;
+    int L;
+
+    real Step = la_CanvasDrawGetDisplayStep(Max, Min, RealH);
+    int IS = Step > 1 ? 0 : (Step > 0.09 ? 1 : 2);
+    t = OrigT = (real)((int)(Min / Step)) * Step;
+    for (t; t <= Max; t += Step, i++){
+        sprintf(buf[i], "%.*f", IS, t);
+        W = tnsStringGetWidth(buf[i], 0, 0);
+        if (W > MaxW) MaxW = W;
+    }
+
+    L = R - MaxW - 4;
+
+    tnsUseNoTexture();
+    for (t = OrigT, i = 0; t <= Max; t += Step, i++){
+        IL[i] = tnsGetRatiod(Max, Min, t) * (RealH);
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(R, IL[i] - hH);
+        tnsVertex2d(R, IL[i] + hH);
+        tnsVertex2d(L, IL[i] + hH);
+        tnsVertex2d(L, IL[i] - hH);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4dv(laThemeColor(bt,LA_BT_TEXT_ACTIVE));
+        tnsVertex2d(R, IL[i] - hH);
+        tnsVertex2d(R, IL[i] + hH);
+        tnsVertex2d(L, IL[i] + hH);
+        tnsVertex2d(L, IL[i] - hH);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    for (t = OrigT, i = 0; t <= Max; t += Step, i++){
+        tnsDrawStringAuto(buf[i], bt->Active, L + 2, R, IL[i] - hH, 0);
+    }
+}
+
+void la_CanvasDraw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    if (ui->CanvasTemplate && ui->CanvasTemplate->Draw) ui->CanvasTemplate->Draw(bt, ui->PP.EndInstance, ui);
+}
+void la_CanvasDrawOverlay(laUiItem *ui, int h){
+    laCanvasExtra *e = ui->Extra;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+
+    tnsDraw2DTextureDirectly(e->OffScr->pColor[0], ui->L, ui->U, ui->R - ui->L, ui->B - ui->U);
+
+    tnsUseNoTexture();
+
+    if(MAIN.CurrentWindow->MaximizedUi!=ui){
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(ui->L, ui->U);
+        tnsVertex2d(ui->R, ui->U);
+        tnsVertex2d(ui->R, ui->B);
+        tnsVertex2d(ui->L, ui->B);
+        tnsPackAs(GL_LINE_LOOP);
+    }
+
+    if (e->DrawCursor){
+        tnsColor4dv(laThemeColor(bt,LA_BT_TEXT));
+        tnsVertex2d(e->OnX, ui->U);
+        tnsVertex2d(e->OnX, ui->B);
+        tnsVertex2d(ui->L, e->OnY);
+        tnsVertex2d(ui->R, e->OnY);
+        tnsPackAs(GL_LINES);
+        tnsFlush();
+    }
+
+    char* MaxIco=(MAIN.CurrentWindow->MaximizedUi!=ui)?"🡹":"🡻";
+    tnsVector4d color; tnsVectorCopy4d(laThemeColor(bt,LA_BT_TEXT),color);
+    color[3]=ui->State==LA_UI_NORMAL?0.0:(ui->State==LA_UI_ACTIVE?0.5:1.0);
+    int startx=(ui->R+ui->L)/2-LA_RH2*2;
+    
+    tnsDrawStringAuto("☰",color,startx, startx+LA_RH, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+    tnsDrawStringAuto(MaxIco,color,startx+LA_RH, startx+LA_2RH, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+
+    if(ui->Expand>=0 && ui!=MAIN.CurrentWindow->MaximizedUi)
+        tnsDrawStringAuto("◿",laThemeColor(bt,LA_BT_BORDER),ui->R-LA_RH, ui->R, ui->B-bt->BM-LA_RH, LA_TEXT_ALIGN_CENTER);
+
+    tnsFlush();
+}
+
+int la_AnimateUiListRecursive(laUiList *uil);
+
+void laDefault3DViewOverlay(laUiItem *ui){
+    laUiList *uil, *gu;
+    laColumn *c, *cl, *cll, *clr, *cr, *crl, *crr, *gc, *gcl, *gcr;
+    laPropPack *e = &ui->ExtraPP;
+    laUiItem *b, *g;
+
+    if (!(uil = ui->Subs.pFirst)) uil = laAddTabPage(ui, "New Group");
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.7);
+    cl = laLeftColumn(c, 0);
+    cr = laRightColumn(c, 0);
+
+    laShowColumnAdjuster(uil, c);
+
+    b=laBeginRow(uil,cl,0,0);
+    laShowLabel(uil,cl,"Active Object: ",0,0);
+    laShowItem(uil,cl,&ui->ExtraPP,"active_object.identifier")->Flags|=LA_UI_FLAGS_PLAIN;
+    laEndRow(uil,b);
+
+    g = laMakeFoldableGroup(uil, cr, "Scene Info", 0, 1);{
+        gu = g->Page;
+        gc = laFirstColumn(gu);
+        laSplitColumn(gu, gc, 0.35);
+        gcl = laLeftColumn(gc, 0);
+        gcr = laRightColumn(gc, 0);
+        laShowItemFull(gu, gc, &ui->PP, 0, LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0);
+        laShowLabel(gu, gcl, "Rename:", 0, 0);
+        laShowItem(gu, gcr, &ui->PP, "name");
+    }
+    g = laMakeFoldableGroup(uil, cr, "Object Info", 0, 0);{
+        gu = g->Page;
+        gc = laFirstColumn(gu);
+        laSplitColumn(gu, gc, 0.35);
+        gcl = laLeftColumn(gc, 0);
+        gcr = laRightColumn(gc, 0);
+        laShowItem(gu, gc, e, "active_object.name");
+        laShowLabel(gu, gcl, "Location:", 0, 0);laShowItem(gu, gcr, e, "active_object.location")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+        laShowSeparator(gu,gc);
+        laShowLabel(gu, gcl, "Rotation:", 0, 0);laShowItem(gu, gcr, e, "active_object.rotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+        laShowItem(gu, gc, e, "active_object.scale");
+    }
+    g = laMakeFoldableGroup(uil, cr, "Display", 0, 1);{
+        gu = g->Page;
+        gc = laFirstColumn(gu);
+        laSplitColumn(gu, gc, 0.35);
+        gcl = laLeftColumn(gc, 0);
+        gcr = laRightColumn(gc, 0);
+
+        laShowLabel(gu, gcl, "Axis:", 0, 0);
+        laWidget w={_LA_UI_ENUM_SELECTOR, LA_UI_FLAGS_ICON|LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_TRANSPOSE};
+        laShowItemFull(gu, gcr, e, "show_axis",&w, "show_prefix=true;" ,0,0);
+        laShowLabel(gu, gcl, "Floor Grid:", 0, 0);
+        laShowItemFull(gu, gcr, e, "show_floor_grid", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
+        laShowItem(gu, gc, e, "grid_size");
+        laShowItem(gu, gc, e, "grid_span");
+
+        //laShowLabel(gu, gcl, "NPR:", 0, 0);
+        //laShowItemFull(gu, gcr, e, "npr_line_mode", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
+    }
+}
+void la_3DViewInit(laUiItem *ui){
+    laCanvasExtra *e = ui->Extra;
+
+    if (e){
+        return;
+    }else{
+        e = memAcquireHyper(sizeof(laCanvasExtra));
+    }
+
+    ui->Extra = e;
+    e->ParentUi = ui;
+
+    tnsVector3d pos={-15, -20, 7};
+    e->ViewingCamera = tnsCreateCamera(0, "VIEWING_CAMERA", rad(50), LA_COLOR3(pos), rad(70), 0, rad(-40), 25);
+    tnsVector3d target={0,0,0}; tnsVector3d up={0,0,1};
+    tnsLookAt(e->ViewingCamera, target, up);
+    e->ViewingCamera->FocusDistance=tnsDist3dv(pos,target);
+
+    e->GridSize = 10;
+    e->GridSpan = 15;
+    e->ShowAxis[0] = 1;
+    e->ShowAxis[1] = 1;
+    e->ShowFloorGrid = 1;
+
+    //e->DisplayMode = LA_3D_VIEW_DISPLAY_WIRE;
+
+    e->HeightCoeff = 10;
+
+    laFirstColumn(laAddTabPage(ui, "New Group"));
+}
+void la_3DViewDestroy(laUiItem *ui){
+    laCanvasExtra *e = ui->Extra;
+
+    tnsDelete2DOffscreen(e->OffScr);
+    tnsDelete2DOffscreen(e->OffScrShadow);
+    
+    tnsDestroyObject(e->ViewingCamera);
+
+    memFree(e);
+}
+
+void laDefault2DViewOverlayRight(laUiItem *ui){
+    laUiList *uil, *gu;
+    laColumn *c, *cr, *crl, *crr, *gc, *gcl, *gcr, *cl;
+    laPropPack *e = &ui->ExtraPP;
+    laUiItem *b, *b1, *b2, *g;
+
+    if (!(uil = ui->Subs.pFirst)) uil = laAddTabPage(ui, "New Group");
+    uil->HeightCoeff=-1;
+
+    c = laFirstColumn(uil);
+    laSplitColumn(uil, c, 0.7);
+    cl = laLeftColumn(c, 0);
+    cr = laRightColumn(c, 0);
+
+    laShowColumnAdjuster(uil, c);
+
+    b=laBeginRow(uil,cl,0,0);
+    laShowLabel(uil, cl, "Line Width:", 0, 0);
+    laShowItem(uil, cl, e, "adaptive_line_width")->Flags|=LA_UI_FLAGS_PLAIN;
+    laEndRow(uil,b);
+
+    b=laBeginRow(uil,cl,0,0);
+    laShowItem(uil, cl, &ui->PP, "size")->Flags|=LA_UI_FLAGS_PLAIN|LA_UI_FLAGS_TRANSPOSE|LA_TEXT_ALIGN_LEFT;
+    laEndRow(uil,b);
+    laShowItem(uil, cl, &ui->PP, "internal_type")->Flags|=LA_UI_FLAGS_PLAIN;
+
+    g = laMakeFoldableGroup(uil, cr, "Display", 0, 1);{
+        gu = g->Page;
+        gc = laFirstColumn(gu);
+        laSplitColumn(gu, gc, 0.35);
+        gcl = laLeftColumn(gc, 0);
+        gcr = laRightColumn(gc, 0);
+
+        // needs another mode for access the ExtraPP.
+        // laShowItem(gu, gc, &ui->ExtraPP, "maximize");
+
+        laShowLabel(gu, gcl, "Transparency:", 0, 0);
+        laShowItem(gu, gcr, e, "draw_image_alpha");
+        laShowLabel(gu, gcl, "Border:", 0, 0);
+        laShowItemFull(gu, gcr, e, "draw_image_border", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
+        laShowLabel(gu, gcl, "Line Width:", 0, 0);
+        laShowItemFull(gu, gcr, e, "adaptive_line_width", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
+        laShowLabel(gu, gcl, "Cursor:", 0, 0);
+        laShowItemFull(gu, gcr, e, "draw_cursor", LA_WIDGET_ENUM_CYCLE, 0, 0, 0);
+    }laEndFoldableGroup(uil,g);
+}
+
+void la_CanvasUiInit(laUiItem* ui){ laCanvasTemplate* ct=ui->CanvasTemplate; if(ct->Init) ct->Init(ui); }
+void la_CanvasUiDestroy(laUiItem *ui){ laCanvasTemplate* ct=ui->CanvasTemplate; if(ct->Destroy) ct->Destroy(ui); }
+
+void la_CanvasInit(laUiItem *ui){
+    laCanvasExtra *e = ui->Extra;
+
+    if (!e){ e = memAcquireHyper(sizeof(laCanvasExtra)); ui->Extra = e; }
+
+    e->ParentUi = ui;
+
+    e->HeightCoeff = 10;
+    e->ZoomX = 1;
+    e->ZoomY = 1;
+    e->ImageDrawAlpha = 1;
+    e->ImageDrawBorder = 1;
+    e->AdaptiveLineWidth = 1;
+    e->ClearBackground = 1;
+
+    laFirstColumn(laAddTabPage(ui, "New Group"));
+}
+void la_CanvasDestroy(laUiItem *ui){
+    laCanvasExtra *e = ui->Extra;
+
+    tnsDelete2DOffscreen(e->OffScr);
+
+    memFree(e);
+}
+
+
+//============================================================= [Operators]
+
+int OPINV_3DOr2DViewUiItem(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    a->CustomData = ui->Extra;
+    return LA_RUNNING;
+}
+int OPEXT_3DOr2DViewUiItem(laOperator *a, int ExitCode){
+    return 0;
+}
+
+int la_CanvasDetectButtons(laUiItem* ui, laBoxedTheme* bt, int x,int y, int total_buttons, int* very_close){
+    int midx=(ui->R+ui->L)/2-LA_RH2*(total_buttons-1), midy=ui->B-LA_RH2-bt->BM;
+    if(y>ui->B-LA_2RH-bt->BM || y<ui->U+LA_2RH+bt->TM || x<ui->L+LA_2RH+bt->TM || x>ui->R-LA_2RH-bt->RM)
+        { if(very_close)*very_close=1; }else return 0;
+    if(y<ui->B-LA_RH-bt->BM)return 0;
+    for(int i=0;i<total_buttons;i++){ if(x>=midx-LA_RH2 && x<midx+LA_RH2) return i+1; midx+=LA_RH;}
+    return 0;
+}
+int OPMOD_Canvas(laOperator *a, laEvent *e){
+    laUiItem *ui = a->Instance;
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    laCanvasExtra *ex = a->CustomData;
+    laUiList *subu;
+    laUiItem *subui = 0;
+    laListHandle Locals = {0};
+    int px = e->x, py = e->y;
+
+    if (!laIsInUiItem(ui, e->x, e->y) && !ex->Dragging){
+        ex->OnX = INT_MAX; ex->OnY = INT_MAX; ui->State=LA_UI_NORMAL;
+        return LA_FINISHED_PASS;
+    }
+
+    //int x=e->x,y=e->y; laPanel*p=MAIN.CurrentPanel,*dp;
+    //laLocalToWindow(0, p, &x, &y); if(!p) p=MAIN.CurrentWindow->MaximizedUiPanel;
+    //if(dp = laDetectPanel(x,y) && dp!=p){ return LA_RUNNING_PASS; }
+
+    if(e->Type&LA_MOUSE_EVENT){
+        if(e->Type == LA_L_MOUSE_DOWN && ui->Expand>=0 && e->x>ui->R-bt->RM-LA_RH && e->y>ui->B-bt->BM-LA_RH){
+            ex->Dragging=1; ex->ClickedX=e->x; ex->ClickedY=e->y; ex->TargetIndexVali=ui->Expand;
+            return LA_RUNNING;
+        }
+        if(ex->Dragging){
+            if(e->Type==LA_MOUSEMOVE){ ui->Expand=ex->TargetIndexVali+((real)e->y-ex->ClickedY+0.5)/LA_RH;
+                if(ex->HeightCoeff<1) ex->HeightCoeff=1; printf("%d\n",ex->HeightCoeff);laRecalcCurrentPanel(); }
+            elif(e->Type==LA_L_MOUSE_UP){ ex->Dragging=0; }
+            elif(e->Type==LA_R_MOUSE_DOWN){ ex->Dragging=0; ui->Expand=ex->TargetIndexVali; laRecalcCurrentPanel(); }
+            return LA_RUNNING;
+        }
+
+        int VeryClose=0; int btn=la_CanvasDetectButtons(ui, bt, e->x, e->y, 2, &VeryClose);
+        if(e->Type==LA_L_MOUSE_DOWN){
+            if(btn==2){ if(MAIN.CurrentWindow->MaximizedUi==ui) laRestoreCanvasUI(); else laMaximizeCanvasUI(ui,MAIN.CurrentPanel); return LA_RUNNING; }
+            if(btn==1){
+                if(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)ui->Flags&=~LA_UI_FLAGS_NO_OVERLAY; else ui->Flags|=LA_UI_FLAGS_NO_OVERLAY;
+                laRedrawCurrentPanel(); return LA_RUNNING;
+            }
+        }
+        int state=VeryClose?(btn?LA_UI_EDITING:LA_UI_ACTIVE):LA_UI_NORMAL;
+        if(state!=ui->State){ ui->State=state;laRedrawCurrentPanel(); }
+    }
+    //laLocalToPanel(a, &px, &py);
+
+    if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){
+        for (subu = ui->Subs.pFirst; subu; subu = subu->Item.pNext){
+            if (subui = la_DetectUiItemRecursive(subu, px, py, ui->B, &Locals, 0)){
+                if (subui && !a->Child && subui->Type->OperatorType){
+                    //printf("invui %d\n", tui);
+                    laUiList *luil = ((laUiListDrawItem *)Locals.pFirst)->Target;
+                    laSetOperatorLocalizer(a->ToPanel);
+                    if (laInvokeUiP(a, subui->Type->OperatorType, e, subui, &Locals, 0) >= 0) laRetriggerOperators();
+                    lstClearPointer(&Locals);
+                    return LA_RUNNING_PASS;
+                }
+            }
+            lstClearPointer(&Locals);
+        }
+    }
+
+    if (ex->DrawCursor){
+        ex->OnX = e->x;
+        ex->OnY = e->y;
+        laRedrawCurrentPanel();
+    }
+
+    if (laKeyMapExecuteEventEx(a, &ui->ExtraPP, &ui->CanvasTemplate->KeyMapper, e)) return LA_RUNNING;
+    if (laKeyMapExecuteEventEx(a, &ui->ExtraPP, &ui->Type->KeyMapper, e)) return LA_RUNNING;
+
+    return LA_RUNNING_PASS;
+}
+
+int OPCHK_Is3DViewExtra(laPropPack *This, laStringSplitor *ss){
+    if (This && This->LastPs->p->SubProp == _LA_PROP_3D_EXTRA) return 1;
+    return 0;
+}
+int OPINV_3DViewCameraZoom(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+    tnsCamera *c = ex->ViewingCamera;
+
+    if (strArgumentMatch(a->ExtraInstructionsP, "direction", "in")){
+        tnsZoomViewingCamera(c, 0.1);
+        laRedrawCurrentPanel();
+    }elif (strArgumentMatch(a->ExtraInstructionsP, "direction", "out")){
+        tnsZoomViewingCamera(c, -0.1);
+        laRedrawCurrentPanel();
+    }
+
+    return LA_FINISHED;
+}
+int OPINV_3DOr2DViewAdjust(laOperator *a, laEvent *e){
+    laGeneralUiExtraData *ex = memAcquireSimple(sizeof(laGeneralUiExtraData));
+    laSetWindowCursor(LA_HAND);
+    a->CustomData = ex;
+    ex->LastX = e->x;
+    ex->LastY = e->y;
+
+    printf("%d %d\n",e->x,e->y);
+
+    return LA_RUNNING;
+}
+int OPEXT_3DOr2DViewAdjust(laOperator *a, int Mark){
+    if (a->CustomData) memFree(a->CustomData);
+    laSetWindowCursor(LA_ARROW);
+}
+int OPMOD_3DViewCameraRotate(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+    laGeneralUiExtraData *uex = a->CustomData;
+
+    if (e->Type == LA_L_MOUSE_UP || e->Type == LA_M_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN) return LA_FINISHED;
+
+    if (e->Type == LA_MOUSEMOVE){
+        tnsRotateViewingCamera(ex->ViewingCamera, (real)(uex->LastY - e->y) / 150.0, (real)(uex->LastX - e->x) / 150.0);
+        uex->LastX = e->x;
+        uex->LastY = e->y;
+        laRedrawCurrentPanel();
+    }
+
+    return LA_RUNNING;
+}
+int OPMOD_3DViewCameraMove(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+    laGeneralUiExtraData *uex = a->CustomData;
+
+    if (e->Type == LA_L_MOUSE_UP || e->Type == LA_M_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN){
+        laSetWindowCursor(LA_ARROW);
+        return LA_FINISHED;
+    }
+    if (e->Type == LA_MOUSEMOVE){
+        tnsTranslateViewingCamera(ex->ViewingCamera, ex->ParentUi->R - ex->ParentUi->L, ex->ParentUi->B - ex->ParentUi->U, -e->x + uex->LastX, e->y - uex->LastY);
+        //tnsTranslateObjectLocal(ex->ViewingCamera,
+        //	-(real)(e->x - uex->LastX) * ex->ViewingCamera->FocusDistance / 100,
+        //	(real)(e->y - uex->LastY) * ex->ViewingCamera->FocusDistance / 100,
+        //	0);
+        uex->LastX = e->x;
+        uex->LastY = e->y;
+        laRedrawCurrentPanel();
+    }
+
+    return LA_RUNNING;
+}
+
+int OPCHK_Is2DViewExtra(laPropPack *This, laStringSplitor *ss){
+    if (This && (This->LastPs->p->SubProp == _LA_PROP_2D_EXTRA)) return 1;
+    return 0;
+}
+int OPINV_CanvasZoom(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+
+    if (strArgumentMatch(a->ExtraInstructionsP, "mode", "mouse")){
+        laGeneralUiExtraData *ex = memAcquireSimple(sizeof(laGeneralUiExtraData));
+        laSetWindowCursor(LA_HAND);
+        a->CustomData = ex;
+        ex->LastX = e->x;
+        ex->LastY = e->y;
+        return LA_RUNNING;
+    }
+
+    if (strArgumentMatch(a->ExtraInstructionsP, "direction", "in")){
+        if (strArgumentMatch(a->ExtraInstructionsP, "axis", "x")){
+            ex->ZoomX *= 0.9;
+        }else{
+            ex->ZoomX *= 0.9;
+            ex->ZoomY *= 0.9;
+        }
+        laRedrawCurrentPanel();
+    }elif (strArgumentMatch(a->ExtraInstructionsP, "direction", "out")){
+        if (strArgumentMatch(a->ExtraInstructionsP, "axis", "x")){
+            ex->ZoomX *= 1.1;
+        }else{
+            ex->ZoomX *= 1.1;
+            ex->ZoomY *= 1.1;
+        }
+        laRedrawCurrentPanel();
+    }
+
+    return LA_FINISHED;
+}
+int OPMOD_CanvasZoom(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+    laGeneralUiExtraData *uex = a->CustomData;
+
+    if (e->Type == LA_L_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN){
+        laSetWindowCursor(LA_ARROW);
+        return LA_FINISHED;
+    }
+
+    if (e->Type == LA_MOUSEMOVE){
+        if (strArgumentMatch(a->ExtraInstructionsP, "axis", "x")){
+            ex->ZoomX *= (1.0 - (e->x - uex->LastX) * MAIN.ZoomSpeed2D);
+        }else{
+            ex->ZoomX *= (1.0 - (e->x - uex->LastX) * MAIN.ZoomSpeed2D);
+            ex->ZoomY *= (1.0 + (e->y - uex->LastY) * MAIN.ZoomSpeed2D);
+        }
+        uex->LastX = e->x;
+        uex->LastY = e->y;
+        laRedrawCurrentPanel();
+    }
+
+    return LA_RUNNING;
+}
+int OPMOD_CanvasMove(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+    laGeneralUiExtraData *uex = a->CustomData;
+
+    if (e->Type == LA_L_MOUSE_UP || e->Type == LA_R_MOUSE_DOWN){
+        laSetWindowCursor(LA_ARROW);
+        return LA_FINISHED;
+    }
+
+    if (e->Type == LA_MOUSEMOVE){
+        if (strArgumentMatch(a->ExtraInstructionsP, "axis", "x")){
+            ex->PanX -= (e->x - uex->LastX) * ex->ZoomX;
+        }else{
+            ex->PanX -= (e->x - uex->LastX) * ex->ZoomX;
+            ex->PanY += (e->y - uex->LastY) * ex->ZoomY;
+        }
+    printf("%d %d\n",e->x,e->y);
+        uex->LastX = e->x;
+        uex->LastY = e->y;
+        laRedrawCurrentPanel();
+    }
+
+    return LA_RUNNING;
+}
+int OPINV_CanvasClick(laOperator *a, laEvent *e){
+    laCanvasExtra *ex = a->This->EndInstance;
+    laGeneralUiExtraData *uex = a->CustomData;
+
+    if (e->Type == LA_L_MOUSE_DOWN){
+        ex->ClickedX = (e->x - (ex->ParentUi->R - ex->ParentUi->L) / 2 - ex->ParentUi->L) * ex->ZoomX + ex->PanX;
+        ex->ClickedY = ((ex->ParentUi->B - ex->ParentUi->U) / 2 - e->y + ex->ParentUi->U) * ex->ZoomY + ex->PanY;
+        laRedrawCurrentPanel();
+    }
+
+    return LA_FINISHED_PASS;
+}
+
+void la_RegisterViewerOperators(){
+    laCreateOperatorType("LA_canvas_operator", "2D View UiItem Operator", "All Visual 2D View Operations Are Called From This Ui",
+                          0, 0, OPEXT_3DOr2DViewUiItem, OPINV_3DOr2DViewUiItem, OPMOD_Canvas, L'🖦', LA_EXTRA_TO_PANEL | LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
+
+    laCreateOperatorType("LA_3d_view_camera_zoom", "Camera Zoom", "Let View Camera Zoom In Or Out",
+                          OPCHK_Is3DViewExtra, 0, 0, OPINV_3DViewCameraZoom, 0, L'🔎', 0);
+    laCreateOperatorType("LA_3d_view_camera_rotate", "Camera Rotate", "Let View Camera Rotate Along Local X/Y Axis",
+                          OPCHK_Is3DViewExtra, 0, OPEXT_3DOr2DViewAdjust, OPINV_3DOr2DViewAdjust, OPMOD_3DViewCameraRotate, L'🗘', LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("LA_3d_view_camera_move", "Camera Move", "Let View Camera Move Along Local X/Y Axis",
+                          OPCHK_Is3DViewExtra, 0, OPEXT_3DOr2DViewAdjust, OPINV_3DOr2DViewAdjust, OPMOD_3DViewCameraMove, L'🤚', LA_EXTRA_TO_PANEL);
+
+    laCreateOperatorType("LA_2d_view_zoom", "2D Zoom", "Let View 2D Cavans Zoom In Or Out",
+                          OPCHK_Is2DViewExtra, 0, OPEXT_3DOr2DViewAdjust, OPINV_CanvasZoom, OPMOD_CanvasZoom, L'🔎', 0);
+    laCreateOperatorType("LA_2d_view_move", "2D Move", "Let View 2D Cavans Move Along Local X/Y Axis",
+                          OPCHK_Is2DViewExtra, 0, OPEXT_3DOr2DViewAdjust, OPINV_3DOr2DViewAdjust, OPMOD_CanvasMove, L'🤚', LA_EXTRA_TO_PANEL);
+    laCreateOperatorType("LA_2d_view_click", "2D Click", "2D Click",
+                          OPCHK_Is2DViewExtra, 0, OPEXT_3DOr2DViewAdjust, OPINV_CanvasClick, 0, L'🖦', LA_EXTRA_TO_PANEL);
+}
+
+
+void *tnsget_detached_FirstScene(void *UNUSED1, void *UNUSED2);
+
+void la_RegisterUiTypesViewerWidgets(){
+    laPropContainer *pc = 0;
+    laProp *p = 0;
+    laKeyMapper *km;
+
+    _LA_UI_CANVAS = la_RegisterUiType("LA_canvas_default", 0, "LA_canvas_operator", &_LA_THEME_2D_VIEW, la_CanvasDraw, la_CanvasGetHeight, la_CanvasUiInit, la_CanvasUiDestroy);
+    _LA_UI_CANVAS->Tag = LA_UI_TAG_NEED_REBUILD;
+
+    laCanvasTemplate* ct=laRegisterCanvasTemplate("la_CanvasDrawTexture", "tns_texture", la_CanvasDrawTexture, la_CanvasDrawOverlay, la_CanvasInit, la_CanvasDestroy);
+    pc = laCanvasHasExtraProps(ct,sizeof(laCanvasExtra),2);{
+        _LA_PROP_2D_EXTRA = pc;
+        laAddIntProperty(pc, "height_coeff", "Ui Height", "Ui Height Coefficiency Entry", 0, 0, "Rows", 100, -100, 1, 0, 0, offsetof(laCanvasExtra, HeightCoeff), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        p = laAddEnumProperty(pc, "draw_image_alpha", "Draw Image Alpha", "Draw Grid Background On Alpha<1", 0, 0, 0, 0, 0,
+                               offsetof(laCanvasExtra, ImageDrawAlpha), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "null", "null", "Don't Draw Grid", 0);
+            laAddEnumItem(p, "normal", "normal", "Use Normal Color", 0);
+            laAddEnumItem(p, "bright", "bright", "Draw Alpha Grid Using Very Bright White Color", 0);
+        }
+        p = laAddEnumProperty(pc, "draw_image_border", "Draw Image Border", "Draw Image Border Using Same Color As Ui Item", 0, 0, 0, 0, 0,
+                               offsetof(laCanvasExtra, ImageDrawBorder), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "no", "No", "Don't Draw Border", L'☐');
+            laAddEnumItem(p, "yes", "Yes", "Draw Border", L'☑');
+        }
+        p = laAddEnumProperty(pc, "adaptive_line_width", "Adaptive Line Width", "glLineWith() will follow 2dview zooming", 0, 0, 0, 0, 0,
+                               offsetof(laCanvasExtra, AdaptiveLineWidth), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "constant", "Constant", "Don't change line width", L'☐');
+            laAddEnumItem(p, "adaptive", "Adaptive", "Adaptive Line Width", L'☑');
+        }
+        p = laAddEnumProperty(pc, "line_width_warning", "Line Width Warnning", "Show whether line width is acceptable by hardware", 0, 0, 0, 0, 0,
+                               offsetof(laCanvasExtra, LineWidthWarning), 0, 0, 0, 0, 0, 0, 0, 0, 0, LA_READ_ONLY);{
+            laAddEnumItem(p, "acceptable", "Acceptable", "Line width is acceptable by graphic hadware", L'✔');
+            laAddEnumItem(p, "too_wide", "Too Wide", "Line width is too wide for graphic hadware", L'❌');
+            laAddEnumItem(p, "too_thin", "Too Thin", "Line width is too thin for graphic hadware", L'❌');
+        }
+        p = laAddEnumProperty(pc, "frame_number", "Frame Number", "Enable Frame Number Display At The Bottom Of The Frame Cursor", 0, 0, 0, 0, 0,
+                               offsetof(laCanvasExtra, ShowFrameNumber), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "hidden", "Hidden", "Don't Draw Frame Number", L'🌔');
+            laAddEnumItem(p, "shown", "Shown", "Draw Frame Number", L'🌑');
+        }
+        p = laAddEnumProperty(pc, "clear_background", "Clear Background", "Clear Background", 0, 0, 0, 0, 0, offsetof(laCanvasExtra, ClearBackground), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "no", "No", "Don't Clear Background", L'🌔');
+            laAddEnumItem(p, "yes", "Yes", "Clear Background", L'🌑');
+        }
+        p = laAddEnumProperty(pc, "draw_cursor", "Show Cursor", "Show Cursor", 0, 0, 0, 0, 0, offsetof(laCanvasExtra, DrawCursor), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "no", "No", "Don't draw cursor", L'🖦');
+            laAddEnumItem(p, "yes", "Yes", "Draw cursor", L'➕');
+        }
+        laAddFloatProperty(pc, "pan", "Pan", "Pan On X,Y Axis", 0, "X,Y", "px", 0, 0, 1, 0, 0, offsetof(laCanvasExtra, PanX), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddFloatProperty(pc, "zoom", "Zoom", "Zoom Factor On X,Y Axis", 0, "X,Y", 0, 0, 0, 0.01, 1, 0, offsetof(laCanvasExtra, ZoomX), 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0);
+        //laAddSubGroup(pc, "Template", "Template Used To Draw 2D Stuff", "la_2d_view_template",0, 0, 0, -offsetof(laCanvasExtra, Template), 0, 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        laAddOperatorProperty(pc, "zoom", "Zoom", "Zoom 2D Canvans", "LA_2d_view_zoom", L'🔎', 0);
+        laAddOperatorProperty(pc, "move", "Move", "Move 2D Canvans", "LA_2d_view_move", L'🤚', 0);
+        laAddOperatorProperty(pc, "click", "Click", "Click On 2D Canvans", "LA_2d_view_click", L'🤚', 0);
+        laAddSubGroup(pc, "parent_ui", "Parent UI", "The Ui That Holds The Viewer", "ui_item",0, 0, 0, offsetof(laCanvasExtra, ParentUi), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+    }
+    km = &ct->KeyMapper;
+    laAssignNewKey(km, 0, "LA_2d_view_zoom", LA_KM_SEL_UI_EXTRA, 0, LA_MOUSE_WHEEL_DOWN, 0, "direction=out");
+    laAssignNewKey(km, 0, "LA_2d_view_zoom", LA_KM_SEL_UI_EXTRA, 0, LA_MOUSE_WHEEL_UP, 0, "direction=in");
+    laAssignNewKey(km, 0, "LA_2d_view_move", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT, LA_L_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "LA_2d_view_click", LA_KM_SEL_UI_EXTRA, 0, LA_L_MOUSE_DOWN, 0, 0);
+
+
+    ct=laRegisterCanvasTemplate("la_3DView", "tns_object", la_RootObjectDraw, la_RootObjectDrawOverlay, la_3DViewInit, la_3DViewDestroy);
+    pc = laCanvasHasExtraProps(ct, sizeof(laCanvasExtra), 2);{
+        _LA_PROP_3D_EXTRA = pc;
+        laAddSubGroup(pc, "active_object", "Active Object", "Active object in this viewport", "tns_object",tnsget_ObjectType, 0, 0, offsetof(laCanvasExtra, ActiveObject), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        laAddIntProperty(pc, "grid_size", "Grid Size", "Floor Grid Size Per Cell", 0, 0, "Unit", 100, 1, 1, 10, 0, offsetof(laCanvasExtra, GridSize), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddIntProperty(pc, "grid_span", "Grid Span", "How Many Grids Are Drawn", 0, 0, 0, 25, 1, 1, 10, 0, offsetof(laCanvasExtra, GridSpan), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        p = laAddEnumProperty(pc, "show_axis", "Show Axis", "Show Global X,Y,Z Axis", LA_WIDGET_ENUM_CYCLE, "X,Y,Z", 0, 0, 0,
+                               offsetof(laCanvasExtra, ShowAxis), 0, 0, 3, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "hidden", "Hidden", "Current Axis Is Hidden", L'🌔');
+            laAddEnumItem(p, "shown", "Shown", "Current Axis Is Shown", L'🌑');
+        }
+        p = laAddEnumProperty(pc, "show_floor_grid", "Show Floor Grid", "Show Floor Grid", 0,  0, 0, 0, 0,
+                               offsetof(laCanvasExtra, ShowFloorGrid), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItem(p, "hidden", "Hidden", "Current Axis Is Hidden", L'🌔');
+            laAddEnumItem(p, "shown", "Shown", "Current Axis Is Shown", L'🌑');
+        }
+        laAddIntProperty(pc, "height_coeff", "Ui Height", "Ui Height Coefficiency Entry", 0, 0, "Rows", 100, -100, 1, 0, 0, offsetof(laCanvasExtra, HeightCoeff), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddOperatorProperty(pc, "zoom", "Zoom", "Zoom Viewing Camera", "LA_3d_view_camera_zoom", L'🔎', 0);
+        laAddOperatorProperty(pc, "rotate", "Rotate", "Rotate Viewing Camera", "LA_3d_view_camera_rotate", L'🗘', 0);
+        laAddOperatorProperty(pc, "move", "Move", "Move Viewing Camera", "LA_3d_view_camera_move", L'🤚', 0);
+        //laAddSubGroup(pc, "Viewing Camera", "Unique Camera That Is Used To Draw 3D Viewport", "tns_object",0, 0, 0, -offsetof(laCanvasExtra, ViewingCamera), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+        laAddSubGroup(pc, "parent_ui", "Parent Ui", "Parent Ui (Mostly Used To Determin Viewport Size)", "ui_item",0, 0, 0, offsetof(laCanvasExtra, ParentUi), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER);
+        laAddOperatorProperty(pc, "align_camera_to_view", "Align Active Camera To View", "Align Active Camera To View", "TNS_align_camera_to_view", L'🎥', 0);
+        laAddOperatorProperty(pc, "align_view_to_camera", "Align View To Active Camera", "Align View To Active Camera", "TNS_align_view_to_camera", L'🎥', 0);
+        laAddOperatorProperty(pc, "_this_M_delete", "Delete", "Delete parts of mesh", "M_delete", 0, 0);
+        laAddOperatorProperty(pc, "_this_M_make_parent", "Make parent", "Parent objects to active objects or unparent selected ones", "M_make_parent", 0, 0);
+        laAddOperatorProperty(pc, "_this_M_unparent", "Unparent", "Unparent selected objects", "M_unparent", 0, 0);
+    }
+
+    km = &ct->KeyMapper;
+    laAssignNewKey(km, 0, "LA_3d_view_camera_zoom", LA_KM_SEL_UI_EXTRA, 0, LA_MOUSE_WHEEL_DOWN, 0, "direction=out");
+    laAssignNewKey(km, 0, "LA_3d_view_camera_zoom", LA_KM_SEL_UI_EXTRA, 0, LA_MOUSE_WHEEL_UP, 0, "direction=in");
+    laAssignNewKey(km, 0, "LA_3d_view_camera_rotate", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT, LA_L_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "LA_3d_view_camera_rotate", LA_KM_SEL_UI_EXTRA, 0, LA_M_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "LA_3d_view_camera_move", LA_KM_SEL_UI_EXTRA, LA_KEY_SHIFT, LA_M_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "LA_3d_view_camera_move", LA_KM_SEL_UI_EXTRA, LA_KEY_SHIFT | LA_KEY_ALT, LA_L_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "TNS_align_camera_to_view", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT | LA_KEY_SHIFT, LA_R_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "TNS_align_view_to_camera", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, '0', 0);
+
+    laAssignNewKey(km, 0, "M_toggle_edit_mode", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, LA_KEY_TAB, 0);
+    laAssignNewKey(km, 0, "M_select", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT, LA_R_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "M_select", LA_KM_SEL_UI_EXTRA, LA_KEY_SHIFT, LA_R_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "M_select", LA_KM_SEL_UI_EXTRA, 0, LA_R_MOUSE_DOWN, 0, 0);
+    laAssignNewKey(km, 0, "M_select", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'b', "mode=box;");
+    laAssignNewKey(km, 0, "M_select", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'a', "mode=toggle;");
+    laAssignNewKey(km, 0, "M_grab", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'g', 0);
+    laAssignNewKey(km, 0, "M_scale", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 's', 0);
+    laAssignNewKey(km, 0, "M_rotate", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'r', 0);
+    laAssignNewKey(km, 0, "M_make_parent", LA_KM_SEL_UI_EXTRA, LA_KEY_CTRL, LA_KEY_DOWN, 'p', 0);
+    laAssignNewKey(km, 0, "M_unparent", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT, LA_KEY_DOWN, 'p', 0);
+    laAssignNewKey(km, 0, "M_clear_transformations", 0, LA_KEY_ALT, LA_KEY_DOWN, 'g', "location=true;text=Clear Location;");
+    laAssignNewKey(km, 0, "M_clear_transformations", 0, LA_KEY_ALT, LA_KEY_DOWN, 'r', "rotation=true;text=Clear Rotation;");
+    laAssignNewKey(km, 0, "M_clear_transformations", 0, LA_KEY_ALT, LA_KEY_DOWN, 's', "scale=true;text=Clear Scale;");
+    laAssignNewKey(km, 0, "M_extrude", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'e', 0);
+    laAssignNewKey(km, 0, "M_extrude", LA_KM_SEL_UI_EXTRA, LA_KEY_SHIFT, LA_KEY_DOWN, 'd', "duplicate_only=true;text=Duplicate;");
+    laAssignNewKey(km, 0, "M_delete", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'x', 0);
+}