*/}}
Browse Source

Edge select

Yiming Wu 2 years ago
parent
commit
9c8b9a126e

+ 12 - 10
source/lagui/la_data.c

@@ -3682,34 +3682,38 @@ void la_ClearUDFRegistryAndFolders(){
 
 //==========================================================================[undo]
 
-void laPushDifferences(char* Description, u64bit hint){
-    memFreeRemainingLeftNodes();
+void laPushDifferenceOnly(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 laPushDifferences(char* Description, u64bit hint){
+    memFreeRemainingLeftNodes();
+    laPushDifferenceOnly(Description,hint);
+}
 
 void la_FreeInstance(void* inst, laPropContainer* pc, int no_free);
 void la_FreeDBInst(laDBInst* dbi, int no_freeinst);
 void la_FreeDBProp(laDBProp* dbp){
+    printf("free dbp %s %x\n",dbp->p->Identifier,dbp);
     if(dbp->p->PropertyType==LA_PROP_SUB){
         if((((laSubProp*)dbp->p)->ListHandleOffset||dbp->p->UDFNoCreate||dbp->p->UDFIsSingle)&&(!dbp->p->UDFIsRefer)){
             laDBSubProp* dsp=dbp; laDBInst* si;
-            //printf("fdbp %s %x\n",dbp->p->Identifier,dsp->Instances.pFirst);
+            printf("fdbp %s %x %x %x\n",dbp->p->Identifier,dsp->Instances.pFirst,dsp->Instances.pLast,((laListItem*)dsp->Instances.pFirst)->pNext);
             while(si=lstPopItem(&dsp->Instances)){ la_FreeDBInst(si,dbp->p->UDFNoCreate||(!dbp->p->OffsetIsPointer)); }
         } // 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, int no_freeinst){
     laListHandle* l=hsh65536DoHashLongPtr(MAIN.DBInstLink,dbi->OriginalInstance); lstRemoveItem(l, &dbi->Item2);
+    printf("free dbi %s %x\n", dbi->pc->Identifier,dbi);
     laDBProp* dbp; while(dbp=lstPopItem(&dbi->Props)){ la_FreeDBProp(dbp); }
     if(dbi->OriginalInstance) la_FreeInstance(dbi->OriginalInstance, dbi->pc, no_freeinst);
     memFree(dbi);
@@ -3740,7 +3744,7 @@ void la_FreeNewerDifferences(){
         PrevD=d->Item.pPrev;
         lstRemoveItem(&MAIN.Differences,d);
         la_FreeDifference(d);
-        if(MAIN.HeadDifference==d){ MAIN.HeadDifference=PrevD; laPushDifferences("desc",0); break; }
+        if(MAIN.HeadDifference==d){ MAIN.HeadDifference=PrevD; laPushDifferenceOnly("desc",0); break; }
     }
 }
 void la_FreeAllDifferences(){
@@ -3960,7 +3964,7 @@ int la_GenerateListDifferences(laDBInst* dbi, laDBSubProp* dbp, laPropPack* pp,
         //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);}
+        laPropContainer* spc=p->SubProp; if(((laSubProp*)p)->GetType){spc=((laSubProp*)p)->GetType(dbi->OriginalInstance);}
         dpi=dbi->Props.pFirst;
         for (subp = spc->Props.pFirst; subp; subp = subp->Item.pNext){
             if (subp->PropertyType == LA_PROP_OPERATOR) continue;
@@ -3968,15 +3972,13 @@ int la_GenerateListDifferences(laDBInst* dbi, laDBSubProp* dbp, laPropPack* pp,
 
             if((!dpi)||dpi->p!=subp) printf("Prop doesn't match\n");
 
-            SubPP.RawThis = pp; SubPS.p = subp; SubPS.UseInstance = inst;
+            SubPP.RawThis = pp; SubPS.p = subp; SubPS.UseInstance = dbi->OriginalInstance;
             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; }
+        dbi=dbi->Item.pNext;
     }
 
     //printf("%x ~ %x\n", dbp->Instances.pFirst, dbp->Instances.pLast);

+ 10 - 20
source/lagui/la_interface.h

@@ -707,13 +707,6 @@ STRUCTURE(laCanvasTemplate){
     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
@@ -725,6 +718,13 @@ STRUCTURE(laCanvasTemplate){
 #define LA_CANVAS_CURSOR_BOX   2
 #define LA_CANVAS_CURSOR_ARROW 3
 
+#define LA_CANVAS_SELECT_MODE_VERTS 0
+#define LA_CANVAS_SELECT_MODE_EDGES 1
+//#define LA_CANVAS_SELECT_MODE_FACES 2
+
+#define LA_CANVAS_SELECT_THROUGH_OFF 0
+#define LA_CANVAS_SELECT_THROUGH_ON  1
+
 STRUCTURE(laCanvasExtra){
     laListItem Item;
     tnsOffscreen *OffScr;
@@ -755,19 +755,10 @@ STRUCTURE(laCanvasExtra){
 
     int ClearBackground;
 
-    //=========== time line display
-
-    int ShowFrameNumber;
-
-    real CursorY;
-
-    int SeletionMode;
-    int SelectStatus;
-    real BL, BR, BU, BB;
+    int SelectMode;
+    int SelectThrough;
     int EditCenter;
-
-    laListHandle PendingList; //Editing FCurve;
-    laListItemPointer *LastSelected;
+    real BL, BR, BU, BB;
 
     int Dragging;
     int TargetIndexVali;
@@ -779,7 +770,6 @@ STRUCTURE(laCanvasExtra){
 
     tnsCamera *ViewingCamera; //Always create this one;
     tnsCamera *UsingCamera;
-    tnsObject *ActiveObject;
     int Layers[20];
     int DisplayMode;
 

+ 2 - 1
source/lagui/la_kernel.c

@@ -403,7 +403,8 @@ void laShutoff(){
     strSafeDestroy(&MAIN.WorkingDirectory);
     strSafeDestroy(&MAIN.example_string);
 
-    la_NoLongerRecordUndo();
+    //la_NoLongerRecordUndo(); XXX: it's not reliable yet, we need to only remove steps that are consistent with current data structure
+    // (Must undo/redo to desired position or delete from back/front without moving target head. This can be done but this is of lower priority. )
 
     laWindow* wi; while(wi=lstPopItem(&MAIN.Windows)){ la_DestroyWindow(wi); }
     laUiTemplate* uit; while(uit=lstPopItem(&MAIN.PanelTemplates)){ la_DestroyUiTemplate(uit); }

+ 8 - 4
source/lagui/la_tns.h

@@ -533,6 +533,7 @@ struct _tnsObject
     tnsMatrix44d SelfTransform;
     //tnsMatrix44d CameraTransform;
 
+    tnsObject *Active;  // may be used to store last select info in child objects.
     tnsObject *InRoot;
     tnsObject *ParentObject;   // reused as root active sun.
     laListHandle ChildObjects;
@@ -1078,12 +1079,15 @@ 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 tnsMMeshSelectEdge(tnsMeshObject* mo, tnsMEdge* me, int select, int toggle);
+void tnsMMeshEnsureSelectionFromVerts(tnsMeshObject* mo);
+void tnsMMeshEnsureSelectionFromEdges(tnsMeshObject* mo);
+void tnsMMeshEnsureSelection(tnsMeshObject* mo, int SelectMode);
 
 void tnsInvaliateMeshBatch(tnsMeshObject* mo);
 void tnsRegenerateMeshBatch(tnsMeshObject* mo);
 void tnsEnsureMeshBatch(tnsMeshObject* mo);
-void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsSelection, tnsMeshObject* Active);
+void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsObjectSelection, int MeshSelectionMode, tnsMeshObject* Active);
 
 void la_RegisterModellingOperators();
 
@@ -1095,8 +1099,8 @@ 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 tnsDrawThisObject(tnsObject *o, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode);
+void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode);
 void tnsDrawScene(int W, int H, tnsObject *root);
 void tnsDrawWorld(int W, int H);
 

+ 5 - 5
source/lagui/la_tns_kernel.c

@@ -3506,11 +3506,11 @@ void tnsDrawCamera(tnsObject *o){
     tnsPackAs(GL_LINE_STRIP);
     tnsFlush();
 }
-void tnsDrawThisObject(tnsObject *o,tnsObject *active, int DrawAsSelection){
+void tnsDrawThisObject(tnsObject *o,tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode){
     if (!o->Show) return;
     switch (o->Type){
     case TNS_OBJECT_MESH:
-        tnsDrawMeshObject(o, DrawAsSelection, active);
+        tnsDrawMeshObject(o, DrawAsObjectSelection, MeshSelectionMode, active);
         break;
     case TNS_OBJECT_CAMERA:
         tnsDrawCamera(o);
@@ -3531,14 +3531,14 @@ void tnsDrawThisObject(tnsObject *o,tnsObject *active, int DrawAsSelection){
     }
 }
 
-void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsSelection){
+void tnsDrawObjectTree(tnsObject *from, tnsObject *active, int DrawAsObjectSelection, int MeshSelectionMode){
     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); }
+        tnsDrawThisObject(o, active, DrawAsObjectSelection, MeshSelectionMode);
+        if (o->ChildObjects.pFirst){ tnsDrawObjectTree(o, active, DrawAsObjectSelection, MeshSelectionMode); }
         tnsPopMatrix();
     }
 }

+ 74 - 26
source/lagui/la_tns_mesh.c

@@ -70,7 +70,7 @@ void tnsInitMeshPlane(tnsMeshObject* mo, real size){
     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);
+    tnsMMeshEnsureSelectionFromVerts(mo);
 }
 
 void tnsTrangulateFaceSimple(tnsMeshObject* mo, tnsFace* f, int* ebuf){
@@ -103,25 +103,40 @@ int* tnsGetTriangulatedBatch(tnsMeshObject* mo, int* totelem){
     *totelem = tottri;
     return ebuf;
 }
-float* tnsGetDrawingVertArray(tnsMeshObject* mo, int* r_totv, int DoIdColors, float** idcolors, int DoEditModeColors, float** editcolors){
+float* tnsGetDrawingVertArray(tnsMeshObject* mo, int* r_totv, int DoIdColors, float** idcolors, int DoEditModeColors, float** editcolors, int** edgeelems, int* r_tote){
     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)); }
+    int totv=mo->Mode==TNS_MESH_EDIT_MODE?mo->totmv:mo->totv; 
+    int tote=mo->Mode==TNS_MESH_EDIT_MODE?mo->totme:mo->tote; *r_tote=tote;
+    int extraverts=DoIdColors?mo->totme*2:0;
+    float* p=calloc(1,(totv+extraverts)*3*sizeof(float)); *r_totv=(totv+extraverts);
+    if(DoIdColors){ (*idcolors)=calloc(1,(totv+extraverts)*3*sizeof(float)); (*edgeelems)=calloc(1,(extraverts)*2*sizeof(int));}
+    if(DoEditModeColors){ (*editcolors)=calloc(1,totv*4*sizeof(float)*extraverts); }
     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;
+            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];
+            }
         }
-        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];
+        for(tnsMEdge*me=mo->me.pFirst;me;me=me->Item.pNext){ int ei=me->i;
+            (*edgeelems)[ei*2]=mo->totmv+ei*2; (*edgeelems)[ei*2+1]=mo->totmv+ei*2+1;
+            float* eidcolor1=&(*idcolors)[(*edgeelems)[ei*2]*3], *eidcolor2=&(*idcolors)[(*edgeelems)[ei*2+1]*3];
+            int id=ei+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;
+            eidcolor1[0]=r;eidcolor1[1]=g;eidcolor1[2]=b;
+            eidcolor2[0]=r;eidcolor2[1]=g;eidcolor2[2]=b;
+            int se1=(*edgeelems)[ei*2];   p[se1*3]=me->vl->p[0]; p[se1*3+1]=me->vl->p[1]; p[se1*3+2]=me->vl->p[2];
+            int se2=(*edgeelems)[ei*2+1]; p[se2*3]=me->vr->p[0]; p[se2*3+1]=me->vr->p[1]; p[se2*3+2]=me->vr->p[2];
+            float* eedcolor1=&(*editcolors)[(*edgeelems)[ei*2]*4], *eedcolor2=&(*editcolors)[(*edgeelems)[ei*2+1]*4];
+            real* c=(me->flags&TNS_MESH_FLAG_SELECTED)?laAccentColor(LA_BT_SEDGE):laAccentColor(LA_BT_EDGE);
+            eedcolor1[0]=c[0]; eedcolor1[1]=c[1]; eedcolor1[2]=c[2]; eedcolor1[3]=c[3];
+            eedcolor2[0]=c[0]; eedcolor2[1]=c[1]; eedcolor2[2]=c[2]; eedcolor2[3]=c[3];
         }
-    } }
+    }
     return p;
 }
 int* tnsGetEdgeBatch(tnsMeshObject* mo){
@@ -142,9 +157,10 @@ void tnsRegenerateMeshBatch(tnsMeshObject* mo){
 
     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; }
+    int totv,tote; int* eelems=0;
+    float* v = tnsGetDrawingVertArray(mo,&totv,docolors,&idcolors,docolors,&editcolors,&eelems,&tote);
+    if(!v){ if(elem){free(elem);} if(eelems){free(eelems);} 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);
@@ -152,23 +168,28 @@ void tnsRegenerateMeshBatch(tnsMeshObject* mo){
 
     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);
+            c= tnsCreateCommand(mo->Batch, "lines", mo->totme, 2, GL_LINES, elem, 1); 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", mo->totmv, 3, GL_POINTS, 0, 1);
         c= tnsCreateCommand(mo->Batch, "verts_select", mo->totmv, 3, GL_POINTS, 0, 1);
         tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
+        c= tnsCreateCommand(mo->Batch, "edges_select", mo->totme, 2, GL_LINES, eelems, 1);
+        tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 3, idcolors);
+        c= tnsCreateCommand(mo->Batch, "edges", mo->totme, 2, GL_LINES, eelems, 1);
+        tnsCommandOverrideColorArray(c, mo->Batch->NumVert, 4, editcolors);
+        for(int i=0;i<mo->totme*2;i++){ printf("%d ",eelems[i]); } printf("\n");
     }
-    if(idcolors) free(idcolors); if(editcolors) free(editcolors);
+    if(idcolors) free(idcolors); if(editcolors) free(editcolors); if(eelems) free(eelems);
 }
 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){
+void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsObjectSelection, int MeshSelectionMode, tnsMeshObject* Active){
     tnsEnsureMeshBatch(mo);
-    if(DrawAsSelection){
+    if(DrawAsObjectSelection){
         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);
@@ -180,7 +201,16 @@ void tnsDrawMeshObject(tnsMeshObject* mo, int DrawAsSelection, tnsMeshObject* Ac
             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);
+        }else{
+            tnsDrawBatch(mo->Batch,"body",0,0);
+            if(mo->Mode==TNS_MESH_EDIT_MODE){
+                if(MeshSelectionMode==LA_CANVAS_SELECT_MODE_VERTS){
+                    tnsDrawBatch(mo->Batch,"verts",0,0); tnsDrawBatch(mo->Batch,"lines",0,0);
+                }else{
+                    tnsDrawBatch(mo->Batch,"edges",0,0);
+                }
+            }
+        }
     }
 }
 
@@ -326,7 +356,7 @@ void tnsMMeshFromMesh(tnsMeshObject* mo){
             tnsMMeshFaceAddEdge(mf,me);
         }
     }
-    tnsMMeshEnsureSelectionFromVert(mo);
+    tnsMMeshEnsureSelectionFromVerts(mo);
     tnsDestroyEdgeHash(eh);
 }
 void tnsMeshFromMMesh(tnsMeshObject* mo){
@@ -378,7 +408,12 @@ void tnsMMeshSelectVert(tnsMeshObject* mo, tnsMVert* mv, int select, int toggle)
     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){
+void tnsMMeshSelectEdge(tnsMeshObject* mo, tnsMEdge* me, int select, int toggle){
+    if(!mo) return;
+    if(toggle) tnsMMeshSelectEdge(mo,me,(me->flags&TNS_MESH_FLAG_SELECTED?0:1),0);
+    elif(select) me->flags|=TNS_MESH_FLAG_SELECTED; else me->flags&=(~TNS_MESH_FLAG_SELECTED);
+}
+void tnsMMeshEnsureSelectionFromVerts(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; 
     }
@@ -387,6 +422,19 @@ void tnsMMeshEnsureSelectionFromVert(tnsMeshObject* mo){
         if(sel){ mf->flags|=TNS_MESH_FLAG_SELECTED; }
     }
 }
+void tnsMMeshEnsureSelectionFromEdges(tnsMeshObject* mo){
+    for(tnsMVert* mv=mo->mv.pFirst;mv;mv=mv->Item.pNext){ mv->flags&=(~TNS_MESH_FLAG_SELECTED);
+        for(laListItemPointer* lip=mv->elink.pFirst;lip;lip=lip->pNext){ tnsMEdge*me=lip->p; if(me->flags&TNS_MESH_FLAG_SELECTED){ mv->flags|=TNS_MESH_FLAG_SELECTED; break; } }
+    }
+    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; }
+    }
+}
+void tnsMMeshEnsureSelection(tnsMeshObject* mo, int SelectMode){
+    if(SelectMode==LA_CANVAS_SELECT_MODE_VERTS){ tnsMMeshEnsureSelectionFromVerts(mo); }
+    elif(SelectMode==LA_CANVAS_SELECT_MODE_EDGES){ tnsMMeshEnsureSelectionFromEdges(mo); }
+}
 
 tnsMeshObject *tnsCreateMeshPlane(tnsObject *under, char *Name, real AtX, real AtY, real AtZ, real size){
     tnsMeshObject *mo; tnsWorld *w = &T->World;

+ 1 - 1
source/lagui/la_util.c

@@ -1115,7 +1115,7 @@ void memTake(void *Data){
 void memFreeRemainingLeftNodes(){
     laListHandle* l; void* m;
     for(int i=0;i<65536;i++){
-        l=&MAIN.DBInstMemLeft->Entries[i]; while(m=lstPopPointer(l)){ memFree(m); /* printf("left freed %x\n",m); */ }
+        l=&MAIN.DBInstMemLeft->Entries[i]; while(m=lstPopPointer(l)){ memFree(m); printf("left freed %x\n",m); }
     }
 }
 

+ 41 - 28
source/lagui/resources/la_modelling.c

@@ -7,13 +7,13 @@ 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;
+    tnsMeshObject* mo=root->Active; 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;
+    tnsMeshObject* mo=root->Active; 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);
@@ -55,10 +55,10 @@ void la_PopulateSelectDataObjects(MSelectData* sd, tnsObject* root, tnsCamera* c
     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);
+    tnsDrawObjectTree(root,0,0,0);
     glDisable(GL_DEPTH_TEST);
 }
-void la_PopulateSelectDataVertices(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera){
+void la_PopulateSelectVerts(MSelectData* sd, tnsMeshObject* mo){
     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){
@@ -66,6 +66,19 @@ void la_PopulateSelectDataVertices(MSelectData* sd, tnsMeshObject* mo, tnsCamera
         sd->Refs[v->i]=v; sd->next=TNS_MAX2(v->i, sd->next);
     }
     sd->next++;
+}
+void la_PopulateSelectEdges(MSelectData* sd, tnsMeshObject* mo){
+    arrEnsureLength(&sd->Refs,0,&sd->max,sizeof(tnsMEdge*));
+    if(mo->Base.Type!=TNS_OBJECT_MESH||!mo->mv.pFirst){ return; }
+    for(tnsMEdge* e=mo->me.pFirst;e;e=e->Item.pNext){
+        arrEnsureLength(&sd->Refs, e->i, &sd->max, sizeof(tnsObject*));
+        sd->Refs[e->i]=e; sd->next=TNS_MAX2(e->i, sd->next);
+    }
+    sd->next++;
+}
+void la_PopulateSelectDataPrimitives(MSelectData* sd, tnsMeshObject* mo, tnsCamera* camera, int WhatPrim){
+    if(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS){ la_PopulateSelectVerts(sd,mo); }
+    elif(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES){ la_PopulateSelectEdges(sd,mo); }
     int w=sd->Color->Width, h=sd->Color->Height;
     tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
     tnsEnableShaderv(T->SelectionShader);
@@ -74,7 +87,7 @@ void la_PopulateSelectDataVertices(MSelectData* sd, tnsMeshObject* mo, tnsCamera
     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);
+    tnsDrawBatch(mo->Batch, (WhatPrim==LA_CANVAS_SELECT_MODE_VERTS)?"verts_select":"edges_select",0,0);
     tnsPopMatrix();
     glDisable(GL_DEPTH_TEST);
 }
@@ -129,9 +142,9 @@ int la_SelectGetClosest(MSelectData* sd, int uix, int uiy, int radius){
         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("%d ",buf[(i*w+j)*4]);
         }
-        //printf("\n");
+        printf("\n");
     }
     free(buf);
     return MinID;
@@ -171,12 +184,13 @@ int OPCHK_ViewportAndSceneExists(laPropPack *This, laStringSplitor *ss){
     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); }
+    if(DeselectAll){ tnsDeselectAllObjects(root); memAssignRef(root,&root->Active,0); }
+    if(o){ tnsSelectObject(o, Select, o==root->Active?0:Toggle); memAssignRef(root,&root->Active,o); }
 }
-void la_DoMeshSelect(tnsMeshObject* mo, tnsMVert* mv, int DeselectAll, int Select, int Toggle){
+void la_DoMeshSelect(tnsMeshObject* mo, void* p, int WhatPrim, int DeselectAll, int Select, int Toggle){
     if(DeselectAll){ tnsMMeshDeselectAll(mo); }
-    if(mv){ tnsMMeshSelectVert(mo,mv,Select,Toggle); }
+    if(p){ if(WhatPrim==LA_CANVAS_SELECT_MODE_VERTS) tnsMMeshSelectVert(mo,p,Select,Toggle);
+        elif(WhatPrim==LA_CANVAS_SELECT_MODE_EDGES) tnsMMeshSelectEdge(mo,p,Select,Toggle);  }
 }
 
 #define LA_SELECT_MODE_BOX 1
@@ -193,7 +207,7 @@ 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;
+    tnsMeshObject* mo=root->Active;
 
     if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"), "toggle")){
         if(mo && mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
@@ -212,16 +226,15 @@ int OPINV_Select(laOperator *a, laEvent *e){
     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);
+        la_PopulateSelectDataPrimitives(sd, mo, ex->ViewingCamera, ex->SelectMode);
         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);
+        int id=la_SelectGetClosest(sd, e->x-ui->L, e->y-ui->U, LA_RH)-1;
+        void* p; if(id>=0 && id<sd->next){ p=sd->Refs[id]; }
+        la_DoMeshSelect(mo, p, ex->SelectMode, DeselectAll, 1, 1); tnsMMeshEnsureSelection(mo,ex->SelectMode);
         tnsInvaliateMeshBatch(mo);
         laNotifyUsers("tns.world"); laRecordAndPush(0,"tns.world");
     }else{
@@ -245,7 +258,7 @@ 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;
+    tnsMeshObject* mo=root->Active;
     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(); }
@@ -260,13 +273,13 @@ int OPMOD_Select(laOperator *a, laEvent *e){
 
     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);
+            la_DoMeshSelect(mo, 0, ex->SelectMode, 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);
+                int id=ids[i]-1; void* p; if(id>=0 && id<se->sd->next){ p=se->sd->Refs[id]; }
+                la_DoMeshSelect(mo, p, ex->SelectMode, 0, !Remove, 0);
             }
-            tnsMMeshEnsureSelectionFromVert(mo);
+            tnsMMeshEnsureSelection(mo,ex->SelectMode);
             tnsInvaliateMeshBatch(mo);
         }else{
             la_DoObjectSelect(se->root, 0, ex, DeselectAll, 0, 0);
@@ -498,7 +511,7 @@ 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;
+    tnsMeshObject* mo=root->Active;
 
     MTransformData* td=la_InitTransformData(ex->OffScr->pColor[0]->Width, ex->OffScr->pColor[0]->Height, c);
     a->CustomData = td;
@@ -535,7 +548,7 @@ 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;
+    tnsMeshObject* mo=root->Active;
     MTransformData* td=a->CustomData;
 
     if (e->Input=='x'||e->Input=='y'||e->Input=='z'||e->Input=='g'||e->Input=='s'||e->Input=='r'||
@@ -602,7 +615,7 @@ 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;
+    tnsObject* mo=root->Active;
 
     int Unparent=0,KeepTransform=1;
     char* action=strGetArgumentString(a->ExtraInstructionsP,"action");
@@ -730,7 +743,7 @@ void la_ExtrudeMakeDuplication(MExtrudeExtra* ee){
         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; }
+        if(de->IsBorder&&me->fl&&me->fr){ ee->RemoveOriginalFaces=1; }
         ee->nexte++;
     }
     for(tnsMFace* mf=mo->mf.pFirst;mf;mf=mf->Item.pNext){
@@ -772,7 +785,7 @@ 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;
+    tnsMeshObject* mo=root->Active; if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE) return 0;
 
     if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
 
@@ -873,7 +886,7 @@ 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;
+    tnsMeshObject* mo=root->Active;
     
     if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){
         if(la_DeleteSelectedObjectsRecursive(root)){

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

@@ -1286,6 +1286,7 @@ void la_RegisterInternalProps(){
             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, "active", "Active", "Active reference", "tns_object",0, 0, 0, offsetof(tnsObject, Active), 0, 0, 0, 0, 0, 0, 0, LA_UDF_REFER|LA_READ_ONLY);
         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);
     }

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

@@ -186,9 +186,14 @@ int la_EnumGetMinWidth(laUiItem *ui){
     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 Highlight=ui->Flags&LA_UI_FLAGS_HIGHLIGHT;
     int SharedWidth;
     if(!IsIcon){
         SharedWidth = bt->LM + bt->RM + ((IsCycle||IsExpand)?0:LA_RH); int HasIcon=0;
+        if(Highlight){
+            tW = tnsStringGetWidth(ep->Base.Name, 0, ui->Flags&LA_TEXT_MONO) + SharedWidth;
+            if (tW > W) W = tW;
+        }
         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; }

+ 32 - 21
source/lagui/resources/la_widgets_viewers.c

@@ -131,11 +131,11 @@ void la_RootObjectDraw(laBoxedTheme *bt, tnsObject *root, laUiItem* ui){
     tnsEnableShaderv(T->immShader);
     tnsUnbindTexture(); tnsUniformUseTexture(T->immShader,0,0); tnsUseMultiplyColor(0);
     glPointSize(6); glLineWidth(3);
-    tnsDrawObjectTree(root, 0, 0);
+    tnsDrawObjectTree(root, 0, 0, e->SelectMode);
     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);
+    tnsDrawObjectTree(root, root->Active, 1, 0);
     glDepthMask(GL_TRUE); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     glLineWidth(1);
 
@@ -430,9 +430,14 @@ void laDefault3DViewOverlay(laUiItem *ui){
 
     laShowColumnAdjuster(uil, c);
 
+    b=laBeginRow(uil,cl,0,0);
+    laShowItem(uil,cl,&ui->ExtraPP,"select_mode")->Flags|=LA_UI_FLAGS_EXPAND;
+    laShowItem(uil,cl,&ui->ExtraPP,"select_through");
+    laEndRow(uil,b);
+
     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;
+    laShowItem(uil,cl,&ui->PP,"identifier")->Flags|=LA_UI_FLAGS_PLAIN;
     laEndRow(uil,b);
 
     g = laMakeFoldableGroup(uil, cr, "Scene Info", 0, 1);{
@@ -451,11 +456,11 @@ void laDefault3DViewOverlay(laUiItem *ui){
         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;
+        laShowItem(gu, gc, &ui->PP, "active.name");
+        laShowLabel(gu, gcl, "Location:", 0, 0);laShowItem(gu, gcr, &ui->PP, "active.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");
+        laShowLabel(gu, gcl, "Rotation:", 0, 0);laShowItem(gu, gcr, &ui->PP, "active.rotation")->Flags|=LA_UI_FLAGS_TRANSPOSE;
+        laShowItem(gu, gc, &ui->PP, "active.scale");
     }
     g = laMakeFoldableGroup(uil, cr, "Display", 0, 1);{
         gu = g->Page;
@@ -872,6 +877,12 @@ void la_RegisterViewerOperators(){
 
 void *tnsget_detached_FirstScene(void *UNUSED1, void *UNUSED2);
 
+void laset_CanvasSelectMode(laCanvasExtra* ex, int mode){
+    ex->SelectMode=mode; laUiItem* ui=ex->ParentUi;
+    tnsObject*root=ui?ui->PP.EndInstance:0; if(!root) return 0;
+    if(root->Active){ if(root->Active->Type==TNS_OBJECT_MESH && ((tnsMeshObject*)root->Active)->Mode==TNS_MESH_EDIT_MODE){ tnsMMeshEnsureSelection(root->Active, mode); } }
+}
+
 void la_RegisterUiTypesViewerWidgets(){
     laPropContainer *pc = 0;
     laProp *p = 0;
@@ -906,11 +917,6 @@ void la_RegisterUiTypesViewerWidgets(){
             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'🌑');
@@ -937,18 +943,23 @@ void la_RegisterUiTypesViewerWidgets(){
     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_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'🌑');
+        }
+        p = laAddEnumProperty(pc, "select_mode", "Select Mode", "Select by vertices or edges", 0, 0, 0, 0, 0, offsetof(laCanvasExtra, SelectMode), 0, laset_CanvasSelectMode, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItemAs(p, "VERTS", "Verts", "Select by vertices", LA_CANVAS_SELECT_MODE_VERTS,0);
+            laAddEnumItemAs(p, "EDGES", "Edges", "Select by edges", LA_CANVAS_SELECT_MODE_EDGES,0);
         }
-        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'🌑');
+        p = laAddEnumProperty(pc, "select_through", "Select Through", "Select through stuff", LA_WIDGET_ENUM_HIGHLIGHT, 0, 0, 0, 0, offsetof(laCanvasExtra, SelectThrough), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);{
+            laAddEnumItemAs(p, "OFF", "Off", "Don't select through stuff", LA_CANVAS_SELECT_THROUGH_OFF,0);
+            laAddEnumItemAs(p, "ON", "On", "Select through stuff", LA_CANVAS_SELECT_THROUGH_ON,0);
         }
         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);