*/}}
Przeglądaj źródła

Shape extrution and deletion seems alright

YimingWu 8 miesięcy temu
rodzic
commit
f4c4653618

+ 4 - 4
la_animation.c

@@ -159,7 +159,7 @@ void laset_AnimationNewActionSetHolder(laNewActionData *np, laActionHolder *ah,
 }
 int OPINV_AnimationNewAction(laOperator *a, laEvent *e){
     laAnimationUpdateHolderList();
-    laNewActionData* np= CreateNew(laNewActionData);
+    laNewActionData* np= memAcquire(sizeof(laNewActionData));
     a->CustomData = np;
     laEnableOperatorPanel(a, 0, e->x-50,e->y-50,500,500,10000,0,0,0,0,0,0,0,e);
     return LA_RUNNING;
@@ -169,7 +169,7 @@ int OPMOD_AnimationNewAction(laOperator *a, laEvent *e){
 
     if(!a->ConfirmData) return LA_RUNNING;
 
-    if(a->ConfirmData->Mode == LA_CONFIRM_CANCEL||a->ConfirmData->Mode == LA_CONFIRM_OK){ if(np) free(np); return LA_CANCELED; }
+    if(a->ConfirmData->Mode == LA_CONFIRM_CANCEL||a->ConfirmData->Mode == LA_CONFIRM_OK){ if(np) memFree(np); return LA_CANCELED; }
 
     if(a->ConfirmData->Mode == LA_CONFIRM_DATA){
         if (!np || !np->SelectedHolder){ if(np) free(np); return LA_CANCELED; }
@@ -651,8 +651,8 @@ void la_AnimationActionDrawOverlay(laUiItem *ui, int h){
 void la_RegisterAnimationResources(){
     laPropContainer *pc; laProp *p; laOperatorType *at; laEnumProp *ep;
 
-    at=laCreateOperatorType("LA_animation_new_action", "New Action", "Add a new action",0,0,0,OPINV_AnimationNewAction,OPMOD_AnimationNewAction,U'🞦',0);
-    pc = laDefineOperatorProps(at, 0);
+    at=laCreateOperatorType("LA_animation_new_action", "New Action", "Add a new action",0,0,OPEXT_FreeUserData,OPINV_AnimationNewAction,OPMOD_AnimationNewAction,U'🞦',0);
+    pc = laDefineOperatorProps(at, 1);
     p = laAddSubGroup(pc, "holder", "Holder", "Action holder to add the new action into", "la_animation_action_holder",
         0, 0, laui_IdentifierOnly, -1, laget_AnimationFirstActionHolder, 0, laget_ListNext, 0, 0, laset_AnimationNewActionSetHolder,0,0);
     laSubGroupExtraFunctions(p,0,0,0,0,laget_AnimationActionHolderCategory);

+ 2 - 1
la_interface.h

@@ -1281,7 +1281,7 @@ 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 void (*laExitFunc)(laOperator *, int);         //true means Quit, false means Cancel
 typedef int (*laInvokeFunc)(laOperator *, laEvent *);
 typedef int (*laModalFunc)(laOperator *, laEvent *);
 typedef int (*laSystemFunc)(laOperator *, laEvent *);
@@ -2271,6 +2271,7 @@ void laRetriggerOperators();
 int la_GenericTopPanelProcessing(laOperator* a, laEvent* e);
 
 int OPMOD_FinishOnData(laOperator* a, laEvent* e);
+void OPEXT_FreeUserData(laOperator* a, int mark_unused);
 
 void laHideCursor();
 void laShowCursor();

+ 8 - 1
la_tns.h

@@ -1197,9 +1197,16 @@ int tnsShapeAnySelected(tnsShapeObject* so);
 void tnsShapeDeselectAll(tnsShapeObject* so);
 void tnsShapeSelectAll(tnsShapeObject* so);
 void tnsShapeSelectPoint(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle, int lr);
+void tnsShapeSelectRingFrom(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle);
+void tnsShapeSetEndPoint(tnsShape* s, tnsSPoint* p);
+void tnsShapeRefreshIndex(tnsShapeObject* so);
+tnsShape* tnsShapeRemovePoint(tnsShapeObject* so, tnsShape* s, tnsSPoint* sp, int SplitShape);
+int tnsShapeConnect(tnsShapeObject* so, tnsShape* s1, tnsShape* s2, tnsSPoint* sp1, tnsSPoint* sp2);
+int tnsShapeConnectSelected(tnsShapeObject* so);
+int tnsShapeExtrudeSelected(tnsShapeObject* so, int DupliOnly);
+
 void tnsShapeEnterEditMode(tnsShapeObject* mo);
 void tnsShapeLeaveEditMode(tnsShapeObject* mo);
-void tnsShapeSelectRingFrom(tnsShapeObject* so, tnsSPoint* sp, int select, int toggle);
 
 NEED_STRUCTURE(la3DObjectDrawExtra);
 

+ 113 - 5
la_tns_shape.c

@@ -31,13 +31,29 @@ tnsSPoint* tnsNewSPoint(tnsShape* s,real x, real y,real ldx,real ldy, real rdx,r
     tnsVectorSet2(sp->p,x,y); tnsVectorSet2(sp->dl,ldx,ldy); tnsVectorSet2(sp->dr,rdx,rdy);
     lstAppendItem(&s->Points,sp); return sp;
 }
+tnsSPoint* tnsShapeInsertSPointAt(tnsShape* s, tnsSPoint* pivot, int before){
+    tnsSPoint* sp=memAcquireSimple(sizeof(tnsSPoint));
+    tnsVectorSet2v(sp->p,pivot->p); tnsVectorSet2v(sp->dl,pivot->dl); tnsVectorSet2v(sp->dr,pivot->dr);
+    if(before){ lstInsertItemBefore(&s->Points,sp,pivot); }
+    else{ lstInsertItemAfter(&s->Points,sp,pivot); }
+}
 void tnsShapeSetClosed(tnsShape* s, int closed, int toggle){
     if(toggle) tnsShapeSetClosed(s,!(s->flags&TNS_SHAPE_CLOSED),0);
     else{ if(closed) s->flags|=TNS_SHAPE_CLOSED; else s->flags&=(~TNS_SHAPE_CLOSED); }
 }
-
+void tnsShapeSetEndPoint(tnsShape* s, tnsSPoint* p){
+    tnsSPoint* ep=s->Points.pLast, *sp=s->Points.pFirst, *np=p->Item.pNext; if(!np || ep==sp || sp->Item.pNext==ep) return;
+    sp->Item.pPrev=ep; ep->Item.pNext=sp; np->Item.pPrev=0; p->Item.pNext=0;
+    s->Points.pFirst=np; s->Points.pLast=p;
+}
+void tnsShapeClearExtraFlags(tnsShapeObject* so){
+    for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){ s->flags&=(~TNS_MESH_FLAG_PICKED);
+        for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_MESH_FLAG_PICKED); }
+    }
+}
 void tnsShapeRefreshIndex(tnsShapeObject* so){
-    u32bit i; for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){
+    u32bit i=0; tnsShape* NextS; for(tnsShape* s=so->Shapes.pFirst;s;s=NextS){ NextS=s->Item.pNext;
+        if(!s->Points.pFirst){ lstRemoveItem(&so->Shapes,s); memLeave(s); continue; }
         for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->i=i; i++; }
     }
 }
@@ -81,6 +97,96 @@ void tnsShapeSelectRingFrom(tnsShapeObject* so, tnsSPoint* sp, int select, int t
     }
 }
 
+tnsShape* tnsShapeRemovePoint(tnsShapeObject* so, tnsShape* s, tnsSPoint* sp, int SplitShape){
+    if(SplitShape && sp->Item.pNext && sp->Item.pPrev){
+        if(s->flags&TNS_SHAPE_CLOSED){ tnsShapeSetEndPoint(s,sp); }
+        tnsShape* ns=tnsNewShape(so); ns->mat=s->mat;
+        tnsSPoint* NextIP; for(tnsSPoint* ip=sp->Item.pNext;ip;ip=NextIP){ NextIP=ip->Item.pNext;
+            tnsSPoint* nsp=tnsNewSPoint(ns,ip->p[0],ip->p[1],ip->dl[0],ip->dl[1],ip->dr[0],ip->dr[1]);
+            nsp->flags=ip->flags; lstRemoveItem(&s->Points,ip);
+        }
+        s->flags&=(~TNS_SHAPE_CLOSED); ns->flags&=(~TNS_SHAPE_CLOSED);
+        lstRemoveItem(&s->Points,sp); memLeave(sp); return ns;
+    }else{
+        lstRemoveItem(&s->Points,sp); memLeave(sp); return 0;
+    }
+}
+int tnsShapeConnect(tnsShapeObject* so, tnsShape* s1, tnsShape* s2, tnsSPoint* sp1, tnsSPoint* sp2){
+    if((sp1!=s1->Points.pFirst && sp1!=s1->Points.pLast) || (sp2!=s2->Points.pFirst && sp2!=s2->Points.pLast)) return 0;
+    if(sp1==s1->Points.pFirst){ lstReverse(&s1->Points);for(tnsSPoint*sp=s1->Points.pFirst;sp;sp=sp->Item.pNext){ LA_SWAP(real,sp->dl[0],sp->dr[0]); LA_SWAP(real,sp->dl[1],sp->dr[1]); } }
+    if(sp2==s2->Points.pLast){ lstReverse(&s2->Points);for(tnsSPoint*sp=s2->Points.pFirst;sp;sp=sp->Item.pNext){ LA_SWAP(real,sp->dl[0],sp->dr[0]); LA_SWAP(real,sp->dl[1],sp->dr[1]); } }
+    tnsSPoint* ip;while(ip=lstPopItem(&s2->Points)){
+        tnsSPoint* nsp=tnsNewSPoint(s1,ip->p[0],ip->p[1],ip->dl[0],ip->dl[1],ip->dr[0],ip->dr[1]);
+        nsp->flags=ip->flags; memLeave(ip);
+    }
+    lstRemoveItem(&so->Shapes.pFirst,s2); memLeave(s2); tnsShapeRefreshIndex(so);
+    return 1;
+}
+int tnsShapeConnectSelected(tnsShapeObject* so){
+    tnsShape* s1=0,*s2=0; tnsSPoint* sp1=0,*sp2=0;
+    for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){ if(s->flags&TNS_SHAPE_CLOSED) continue;
+        if(!s1){
+            if(((tnsSPoint*)s->Points.pFirst)->flags&TNS_MESH_FLAG_SELECTED){ s1=s;sp1=s->Points.pFirst; }
+            elif(((tnsSPoint*)s->Points.pLast)->flags&TNS_MESH_FLAG_SELECTED){ s1=s;sp1=s->Points.pLast; }
+        }else{
+            if(((tnsSPoint*)s->Points.pFirst)->flags&TNS_MESH_FLAG_SELECTED){ s2=s;sp2=s->Points.pFirst; break; }
+            elif(((tnsSPoint*)s->Points.pLast)->flags&TNS_MESH_FLAG_SELECTED){ s2=s;sp2=s->Points.pLast; break; }
+        }
+    }
+    if(s1&&s2&&sp1&&sp2){ return tnsShapeConnect(so,s1,s2,sp1,sp2); } return 0;
+}
+int tnsShapeExtrudeSelected(tnsShapeObject* so, int DupliOnly){
+    laListHandle* pairs; tnsShape* NextS; int any=0;
+    for(tnsShape* s=so->Shapes.pFirst;s;s=NextS){ NextS=s->Item.pNext;
+        if(s->flags&TNS_MESH_FLAG_PICKED){ continue; }
+        tnsSPoint* PrevSP=0,*NextSP=0,*nsp=0;
+        tnsShape* ns=0; int broken=0;
+        for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
+            if(!(sp->flags&TNS_MESH_FLAG_SELECTED)){ broken=1; break; }
+        }
+        if(!broken){ any=1;
+            tnsShape* ns=tnsNewShape(so); for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){
+                tnsSPoint* nsp=tnsNewSPoint(ns,sp->p[0],sp->p[1],sp->dl[0],sp->dl[1],sp->dr[0],sp->dr[1]); nsp->flags=sp->flags;
+            }
+            ns->flags=(s->flags|TNS_MESH_FLAG_PICKED); ns->mat=s->mat;
+            for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_SPOINT_SELECTED); } continue;
+        }
+        for(tnsSPoint* sp=s->Points.pFirst;sp;sp=NextSP){ NextSP=sp->Item.pNext;
+            if(!(sp->flags&TNS_MESH_FLAG_SELECTED)){ PrevSP=sp; continue; }
+            int doprev=0,donext=0;
+            if((!PrevSP) || (PrevSP->flags^sp->flags)&TNS_MESH_FLAG_SELECTED){ doprev=1; }
+            if((!NextSP) || (NextSP->flags^sp->flags)&TNS_MESH_FLAG_SELECTED){ donext=1; }
+            if(DupliOnly){
+                if(doprev){ ns=tnsNewShape(so); ns->flags=(s->flags&(~TNS_SHAPE_CLOSED));
+                    ns->flags|=TNS_MESH_FLAG_PICKED; ns->mat=s->mat; any=1;
+                }
+                if(ns){ nsp=tnsNewSPoint(ns,sp->p[0],sp->p[1],sp->dl[0],sp->dl[1],sp->dr[0],sp->dr[1]);
+                    nsp->flags=sp->flags;
+                }
+                if(donext){ ns=0; }
+            }else{
+                if(!(doprev&&donext)){ any=1;
+                    if(doprev) tnsShapeInsertSPointAt(s,sp,1);
+                    elif(donext) tnsShapeInsertSPointAt(s,sp,0);
+                }else{
+                    if((!NextSP) && donext){ tnsShapeInsertSPointAt(s,sp,1); }
+                    else{ tnsShapeInsertSPointAt(s,sp,0); }
+                }
+            }
+            PrevSP=sp;
+        }
+    }
+    if(DupliOnly){
+        for(tnsShape* s=so->Shapes.pFirst;s;s=NextS){ NextS=s->Item.pNext;
+            if(s->flags&TNS_MESH_FLAG_PICKED){ continue; }
+            for(tnsSPoint* sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ sp->flags&=(~TNS_SPOINT_SELECTED); }
+        }
+    }
+    tnsShapeClearExtraFlags(so);
+    tnsShapeRefreshIndex(so);
+    return any;
+}
+
 void tnsShapeEnterEditMode(tnsShapeObject* so){
     if(so->Mode==TNS_MESH_EDIT_MODE) return;
     so->Mode = TNS_MESH_EDIT_MODE;
@@ -165,7 +271,7 @@ void tns_DrawShape(tnsShape* s, real* override_color, int DrawEdit, real PointSc
     if(DrawEdit || (!closed)){
         tnsVector4d color; tnsVectorCopy4d(laAccentColor(LA_BT_VERTEX),color);
         real* ActiveColor=laAccentColor(LA_BT_SVERTEX);
-        if(!HasSelection) color[3]*=0.4;
+        if(DrawEdit && (!HasSelection)) color[3]*=0.4;
         nvgStrokeColor(vg,override_color?nvgRGBAf(LA_COLOR4(override_color)):nvgRGBAf(LA_COLOR4(color)));
         nvgStrokeWidth(vg,PointScale*4);
         if(!DrawEdit){nvgShapeAntiAlias(vg,0);nvgStroke(vg);nvgShapeAntiAlias(vg,1);return;}
@@ -313,11 +419,14 @@ int OPINV_SetShapeClosed(laOperator *a, laEvent *e){
     tnsShapeObject* so=root->Active; int ran=0;
 
     char* mode=strGetArgumentString(a->ExtraInstructionsP,"mode");
+    char* res=strGetArgumentString(a->ExtraInstructionsP,"reset");
     int set=2; if(strSame(mode,"CLOSE")){ set=1; }elif(strSame(mode,"OPEN")){ set=0; }
+    int reset=0; if(strSame(res,"TRUE")){ reset=1; }
 
     for(tnsShape*s=so->Shapes.pFirst;s;s=s->Item.pNext){
         for(tnsSPoint*sp=s->Points.pFirst;sp;sp=sp->Item.pNext){ if(!(sp->flags&TNS_SPOINT_SELECTED)) continue;
-            tnsShapeSetClosed(s,set,set==2); ran=1; break;
+            if(reset){ tnsShapeSetEndPoint(s,sp); tnsShapeRefreshIndex(so); tnsShapeSetClosed(s,0,0); }
+            else{ tnsShapeSetClosed(s,set,set==2); } ran=1; break;
         }
     }
     if(ran){
@@ -333,5 +442,4 @@ void la_RegisterShapeOperators(){
     at=laCreateOperatorType("M_set_point_handle", "Set Point Handle", "Set handle type of selected points",OPCHK_IsAnyPointSelected,0,0,OPINV_SetPointHandle,OPMOD_FinishOnData,0,0);
     at->UiDefine=laui_SetPointHandle;
     at=laCreateOperatorType("M_set_shape_closed", "Set Shape Closed", "Set shape closed or open",OPCHK_IsAnyPointSelected,0,0,OPINV_SetShapeClosed,0,0,0);
-    
 }

+ 84 - 43
resources/la_modelling.c

@@ -1144,23 +1144,25 @@ 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=root->Active; if(mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE) return 0;
+    tnsMeshObject* mo=root->Active; tnsShapeObject* so=mo; if(!mo) return 0;
 
-    if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
-
-    MExtrudeExtra* ee=la_InitExtrude(mo);
-
-    la_ExtrudeMakeDuplication(ee);
-    
-    if(strSame(strGetArgumentString(a->ExtraInstructionsP,"duplicate_only"), "true")){
+    if(mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
+        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, 1);
+            if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
+        }
+        la_RemoveOriginalFaces(ee);
+        la_ReconnectFaces(ee);
         la_FinishExtrude(ee, 1);
-        if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
+    }elif(so->Base.Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){
+        int duponly=strSame(strGetArgumentString(a->ExtraInstructionsP,"duplicate_only"), "true");
+        tnsShapeExtrudeSelected(so,duponly);
+    }else{
+        return LA_CANCELED;
     }
-
-    la_RemoveOriginalFaces(ee);
-    la_ReconnectFaces(ee);
-
-    la_FinishExtrude(ee, 1);
     if(la_InitTransform(a, e, LA_TRANSFORM_MODE_GRAB,0,0)) return LA_RUNNING; return LA_FINISHED;
 
     return LA_FINISHED;
@@ -1235,6 +1237,15 @@ void la_DeleteFaces(tnsMeshObject* mo, int OnlyFaces){
         tnsMVert* mv; while(mv=lstPopPointer(&lv)){ tnsMMeshRemoveVertEdgeFace(mo,mv); }
     }
 }
+void la_DeletePoints(tnsShapeObject* so, int SplitShape){
+    for(tnsShape* s=so->Shapes.pFirst;s;s=s->Item.pNext){
+        tnsSPoint* NextSP; for(tnsSPoint* sp=s->Points.pFirst;sp;sp=NextSP){ NextSP=sp->Item.pNext;
+            if(!(sp->flags&TNS_MESH_FLAG_SELECTED)) continue;      
+            tnsShapeRemovePoint(so,s,sp,SplitShape);      
+        }
+    }
+    tnsShapeRefreshIndex(so);
+}
 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);
@@ -1242,17 +1253,17 @@ int la_DeleteSelectedObjectsRecursive(tnsObject* root){
     }
     return any;
 }
+STRUCTURE(MDeleteData){
+    int _PAD;
+    int Context;
+};
 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=root->Active; if(!mo) return 0;
+    tnsMeshObject* mo=root->Active; tnsShapeObject* so=mo; if(!mo) return 0;
     
-    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(mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
         if(!tnsMMeshAnySelected(mo)) return LA_FINISHED;
         if(strSame(strGetArgumentString(a->ExtraInstructionsP, "mode"),"vertices")){
             la_DeleteVertices(mo);
@@ -1263,23 +1274,43 @@ int OPINV_Delete(laOperator *a, laEvent *e){
         }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;
+            MDeleteData* md=memAcquire(sizeof(MDeleteData)); a->CustomData=md; md->Context=TNS_OBJECT_MESH;
+            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);
         tnsInvalidateMeshBatch(mo);
         laRecordInstanceDifferences(mo, "tns_mesh_object"); laPushDifferences("Deleted primitives", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
+    }if(so->Base.Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){
+        if(!tnsShapeAnySelected(so)) return LA_FINISHED;
+        char* split=strGetArgumentString(a->ExtraInstructionsP, "split");
+        if(split){
+            int SplitShapes=strSame(split,"TRUE"); la_DeletePoints(so,SplitShapes);
+        }else{
+            MDeleteData* md=memAcquire(sizeof(MDeleteData)); a->CustomData=md; md->Context=TNS_OBJECT_SHAPE;
+            laEnableOperatorPanel(a,a->This,e->x,e->y,200,200,0,0,0,0,0,0,0,0,e); return LA_RUNNING;
+        }
+        laRecordInstanceDifferences(so, "tns_shape_object"); laPushDifferences("Deleted points", TNS_HINT_GEOMETRY); laNotifyUsers("tns.world");
+    }else{
+        if(la_DeleteSelectedObjectsRecursive(root)){
+            laRecordInstanceDifferences(T->World, "tns_world"); laPushDifferences("Deleted objects", TNS_HINT_TRANSFORM); 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);
+    laColumn* c=laFirstColumn(uil); laUiItem* b;
+    b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(TNS_OBJECT_MESH)));{
+        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);
+    }laEndCondition(uil,b);
+    b=laOnConditionThat(uil,c,laEqual(laPropExpression(actinst,"context"),laIntExpression(TNS_OBJECT_SHAPE)));{
+        laShowItemFull(uil,c,pp,"_this_M_delete",0,"split=FALSE;",0,0);
+        laShowItemFull(uil,c,pp,"_this_M_delete",0,"split=TRUE;text=Delet and Split",0,0);
+    }laEndCondition(uil,b);
 }
 
 STRUCTURE(MIslandInfo){
@@ -1396,20 +1427,27 @@ int OPINV_Make(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=root->Active;
+    tnsMeshObject* mo=root->Active; tnsShapeObject*so=mo;
     
-    if(!mo||mo->Base.Type!=TNS_OBJECT_MESH || mo->Mode!=TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
+    if(!mo){ return LA_CANCELED; }
 
-    MMakeData md={0};
-    la_GetSelectionIslands(mo,&md,ex->SelectMode);
-    int success=la_MakeFacesFromIslands(mo,&md); if(success){ tnsMMeshCalculateNormal(mo); }
-    la_ClearIslands(&md);
+    if(mo->Base.Type==TNS_OBJECT_MESH && mo->Mode==TNS_MESH_EDIT_MODE){
+        MMakeData md={0};
+        la_GetSelectionIslands(mo,&md,ex->SelectMode);
+        int success=la_MakeFacesFromIslands(mo,&md); if(success){ tnsMMeshCalculateNormal(mo); }
+        la_ClearIslands(&md);
 
-    tnsMMeshRefreshIndex(mo);
-    tnsMMeshEnsureSelection(mo,ex->SelectMode);
-    tnsInvalidateMeshBatch(mo);
-    if(laRecordInstanceDifferences(mo, "tns_mesh_object")) laPushDifferences("Make primitives", TNS_HINT_GEOMETRY);
-    laNotifyUsers("tns.world");
+        tnsMMeshRefreshIndex(mo);
+        tnsMMeshEnsureSelection(mo,ex->SelectMode);
+        tnsInvalidateMeshBatch(mo);
+        if(laRecordInstanceDifferences(mo, "tns_mesh_object")) laPushDifferences("Make primitives", TNS_HINT_GEOMETRY);
+        laNotifyUsers("tns.world");
+    }elif(so->Base.Type==TNS_OBJECT_SHAPE && so->Mode==TNS_MESH_EDIT_MODE){
+        if(tnsShapeConnectSelected(so)){
+            laRecordInstanceDifferences(so, "tns_shape_object"); laPushDifferences("Connect shapes", TNS_HINT_GEOMETRY);
+            laNotifyUsers("tns.world");
+        }
+    }
     
     return LA_FINISHED;
 }
@@ -1566,9 +1604,10 @@ int OPINV_Duplicate(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 LA_CANCELED;
-    tnsMeshObject* mo=root->Active; int ran=0;
+    tnsMeshObject* mo=root->Active; tnsShapeObject* so=mo; int ran=0;
     
-    if(!mo || mo->Mode==TNS_MESH_EDIT_MODE){ return LA_CANCELED; }
+    if(!mo || (mo->Base.Type==TNS_OBJECT_MESH&&mo->Mode==TNS_MESH_EDIT_MODE)||
+        (so->Base.Type==TNS_OBJECT_SHAPE&&so->Mode==TNS_MESH_EDIT_MODE)){ return LA_CANCELED; }
 
     laListHandle pending={0}; la_PopulateSelectedObjects(root,&pending,0);
     tnsMeshObject* o; tnsMeshObject* no; laListItemPointer* lip;
@@ -1971,12 +2010,14 @@ void la_RegisterModellingOperators(){
     at=laCreateOperatorType("M_unparent", "Unparent", "Unparent selected objects", 0, 0, 0, OPINV_MakeParent, OPMOD_FinishOnData, 0, 0);
     at->UiDefine = laui_Unparent;
     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=laCreateOperatorType("M_delete", "Delete", "Delete parts of the mesh", 0, 0, OPEXT_FreeUserData, OPINV_Delete, OPMOD_FinishOnData, 0, 0);
+    pc = laDefineOperatorProps(at, 1);
+    laAddIntProperty(pc,"context","Context","Delete menu context",0,0,0,0,0,0,0,0,offsetof(MDeleteData,Context),0,0,0,0,0,0,0,0,0,0,0);
     at->UiDefine=laui_Delete;
     laCreateOperatorType("M_make", "Make", "Make mesh primitive from selected ones", 0, 0, 0, OPINV_Make, 0, 0, 0);
     laCreateOperatorType("M_subdiv", "Subdiv", "Subdivide edges", 0, 0, 0, OPINV_Subdiv, 0, 0, 0);
-    at=laCreateOperatorType("M_add", "Add", "Add mesh or primitives", 0, 0, 0, OPINV_Add, OPMOD_FinishOnData, 0, 0);
-    at->UiDefine=laui_Add; pc = laDefineOperatorProps(at, 2);
+    at=laCreateOperatorType("M_add", "Add", "Add mesh or primitives", 0, 0, OPEXT_FreeUserData, OPINV_Add, OPMOD_FinishOnData, 0, 0);
+    at->UiDefine=laui_Add; pc = laDefineOperatorProps(at, 1);
     p=laAddEnumProperty(pc,"context","Context","Context of adding",0,0,0,0,0,offsetof(laObjectAddData,Context),0,0,0,0,0,0,0,0,0,0);
     laAddEnumItemAs(p,"OBJECT","Object","Object context",LA_ADD_CTX_OBJECT,0);
     laAddEnumItemAs(p,"MESH","Mesh","Mesh context",LA_ADD_CTX_MESH,0);

+ 13 - 12
resources/la_operators.c

@@ -59,6 +59,9 @@ int OPMOD_FinishOnData(laOperator* a, laEvent* e){
     }
     return LA_RUNNING;
 }
+void OPEXT_FreeUserData(laOperator* a, int mark_unused){
+    if(a->CustomData) memFree(a->CustomData);
+}
 int OPCHK_AlwaysTrue(laPropPack *pp, laStringSplitor *ss){
     return 1;
 }
@@ -308,7 +311,7 @@ void la_FileBrowserRebuildList(laFileBrowser *fb){
     fb->Active = 0;
 }
 laFileBrowser *la_FileBrowserInit(laOperator *a){
-    laFileBrowser *fb = memAcquireHyper(sizeof(laFileBrowser));
+    laFileBrowser *fb = memAcquire(sizeof(laFileBrowser));
     char* arg=0;
 
     strcpy(fb->Path, MAIN.WorkingDirectory->Ptr);
@@ -446,7 +449,7 @@ int OPINV_FileBrowser(laOperator *a, laEvent *e){
     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){
+void OPEXT_FileBrowser(laOperator *a, int mark){
     laFileBrowser *fb = a->CustomData;
     void* f;
     while (f=lstPopItem(&fb->Disks)) memFree(f);
@@ -454,7 +457,6 @@ int OPEXT_FileBrowser(laOperator *a, int mark){
     while (f=lstPopItem(&fb->Bookmarks)) memFree(f);
     strDestroyStringSplitor(&fb->ss_filter_extensions);
     memFree(fb);
-    return 0;
 }
 int OPMOD_FileBrowser(laOperator *a, laEvent *e){
     laFileBrowser *fb = a->CustomData;
@@ -530,7 +532,7 @@ int OPMOD_FileBrowserConfirm(laOperator *a, laEvent *e){
 }
 
 void la_DestroyUDFContentNodeTreeRecursive(laUDFContentNode* ucn, int FreeRoot);
-int OPEXT_UDFOperation(laOperator *a, laEvent *e){
+void OPEXT_UDFOperation(laOperator *a, laEvent *e){
     laUDFPreviewExtra *upe = a->CustomData;
     laUDFContentNode *ucni, *NextUCNI;
     for (ucni = upe->ContentNodes.pFirst; ucni; ucni = NextUCNI){
@@ -596,7 +598,7 @@ void laset_ManagedSavePage(laManagedSaveExtra* mse, int p){
     laRegisterModifications(0,0,0,0);
 }
 
-int OPEXT_ManagedSave(laOperator *a, laEvent *e){
+void OPEXT_ManagedSave(laOperator *a, laEvent *e){
     laManagedSaveExtra *upe = a->CustomData;
     memFree(upe);
 }
@@ -981,7 +983,7 @@ int OPINV_RemoveLayout(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 int OPINV_NewPanel(laOperator *a, laEvent *e){
-    laNewPanelData* np= CreateNew(laNewPanelData);
+    laNewPanelData* np= memAcquire(sizeof(laNewPanelData));
     a->CustomData = np;
     laEnableOperatorPanel(a, 0, e->x-50,e->y-50,500,500,10000,0,0,0,0,0,0,0,e);
     return LA_RUNNING;
@@ -992,15 +994,15 @@ int OPMOD_NewPanel(laOperator *a, laEvent *e){
 
     if(!a->ConfirmData) return LA_RUNNING;
 
-    if(a->ConfirmData->Mode == LA_CONFIRM_CANCEL||a->ConfirmData->Mode == LA_CONFIRM_OK){ if(np) free(np);  return LA_CANCELED; }
+    if(a->ConfirmData->Mode == LA_CONFIRM_CANCEL||a->ConfirmData->Mode == LA_CONFIRM_OK){ if(np) memFree(np);  return LA_CANCELED; }
 
     if(a->ConfirmData->Mode == LA_CONFIRM_DATA){
-        if (!np || !np->SelectedTemplate){ if(np) free(np); return LA_CANCELED; }
+        if (!np || !np->SelectedTemplate){ if(np) memFree(np); 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,0,0,0,0,0,0,0,0,0,0);
         }
-        laShowPanelWithExpandEffect(p); laPopPanel(p); free(np);
+        laShowPanelWithExpandEffect(p); laPopPanel(p); memFree(np);
         return LA_FINISHED;
     }
 
@@ -1551,9 +1553,8 @@ int OPINV_Panel(laOperator *a, laEvent *e){
     laRetriggerOperators();
     return LA_RUNNING;
 }
-int OPEXT_Panel(laOperator *a, int ExitCode){
+void OPEXT_Panel(laOperator *a, int ExitCode){
     memFree(a->CustomData);
-    return 0;
 }
 int la_ScrollPanel(laGeneralUiExtraData*ex, laPanel*p, laEvent* e){
     int ret=0;
@@ -2075,7 +2076,7 @@ void la_RegisterBuiltinOperators(){
     laCreateOperatorType("LA_file_dialog_up", "Up", "Select Upper Folder Level", OPCHK_IsFileBrowser, 0, 0, OPINV_FileBrowserUpLevel, 0, U'🢰', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
     laCreateOperatorType("LA_file_dialog_confirm", "Confirm", "Confirm selection", OPCHK_FileBrowserCanConfirm, 0, 0, OPINV_FileBrowserConfirm, OPMOD_FileBrowserConfirm, U'✔', LA_ACTUATOR_SYSTEM | LA_ACTUATOR_HIDDEN);
     at = laCreateOperatorType("LA_file_dialog", "File Dialog", "Do File Operations", 0, 0, OPEXT_FileBrowser, OPINV_FileBrowser, OPMOD_FileBrowser, U'🗐', LA_ACTUATOR_SYSTEM);
-    pc = laDefineOperatorProps(at, 2);
+    pc = laDefineOperatorProps(at, 1);
     at->UiDefine = laui_FileBrowserFileList;
     _LA_PROP_FILE_BROWSER = pc;
 

+ 1 - 1
resources/la_widgets.c

@@ -293,8 +293,8 @@ int la_ButtonGetMinWidth(laUiItem *ui){
     if (ui->PP.LastPs && ui->PP.LastPs->p){
         ap = ui->PP.LastPs->p;
         label = transLate(ap->Base.Name);
-        IconID = ap->Base.IconID ? ap->Base.IconID : ap->OperatorType->IconID;
         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;

+ 3 - 2
resources/la_widgets_viewers.c

@@ -1198,6 +1198,7 @@ void la_RegisterUiTypesViewerWidgets(){
     laAssignNewKey(km, 0, "M_knife", LA_KM_SEL_UI_EXTRA, LA_KEY_CTRL, LA_KEY_DOWN, 'r', "mode=loop_cut");
     laAssignNewKey(km, 0, "M_merge", LA_KM_SEL_UI_EXTRA, LA_KEY_ALT, LA_KEY_DOWN, 'm', 0);
 
-    laAssignNewKey(km, 0, "M_set_point_handle", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'q', 0);
-    laAssignNewKey(km, 0, "M_set_shape_closed", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 't', 0);
+    laAssignNewKey(km, 0, "M_set_point_handle", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'v', 0);
+    laAssignNewKey(km, 0, "M_set_shape_closed", LA_KM_SEL_UI_EXTRA, 0, LA_KEY_DOWN, 'q', 0);
+    laAssignNewKey(km, 0, "M_set_shape_closed", LA_KM_SEL_UI_EXTRA, LA_KEY_SHIFT, LA_KEY_DOWN, 'q', "reset=TRUE");
 }