|  | @@ -41,7 +41,9 @@ laActionChannel* laAnimationEnsureChannel(laAction* aa, void* hyper1, laProp* p)
 | 
	
		
			
				|  |  |      acf=memAcquire(sizeof(laActionChannel));
 | 
	
		
			
				|  |  |      memAssignRef(acf,&acf->For,hyper1); acf->Prop=p;
 | 
	
		
			
				|  |  |      acf->DataSize = DataSize;
 | 
	
		
			
				|  |  | -    lstAppendItem(&aa->Channels,acf);
 | 
	
		
			
				|  |  | +    char _name[128]={0}, *name=_name; laTryGetInstanceIdentifier(hyper1, p->Container,_name,&name);
 | 
	
		
			
				|  |  | +    strSafeSet(&acf->CachedName,name); strSafePrint(&acf->CachedName," ⯈ %s",p->Identifier);
 | 
	
		
			
				|  |  | +    lstAppendItem(&aa->Channels,acf); laNotifyUsers("la.animation.current_action.channels");
 | 
	
		
			
				|  |  |      return acf;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame){
 | 
	
	
		
			
				|  | @@ -53,7 +55,7 @@ laActionChannel* laAnimationEnsureFrame(laActionChannel* ac, int frame){
 | 
	
		
			
				|  |  |          akf=memAcquireSimple(sizeof(laActionKey)-sizeof(uint64_t)+ac->DataSize);
 | 
	
		
			
				|  |  |          akf->At=frame;
 | 
	
		
			
				|  |  |          if(beforeakf){ lstInsertItemBefore(&ac->Keys, akf, beforeakf); }
 | 
	
		
			
				|  |  | -        lstAppendItem(&ac->Keys, akf);
 | 
	
		
			
				|  |  | +        else{ lstAppendItem(&ac->Keys, akf); }
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      return akf;
 | 
	
		
			
				|  |  |  }
 | 
	
	
		
			
				|  | @@ -73,6 +75,7 @@ laActionKey* laAnimationInsertKeyFrame(laAction* aa, void* hyper1, laProp* p){
 | 
	
		
			
				|  |  |      int frame=LA_ACTION_FRAME(aa);
 | 
	
		
			
				|  |  |      laActionKey* ak=laAnimationEnsureFrame(ac,frame);
 | 
	
		
			
				|  |  |      laAnimationStoreKeyValue(ac,ak);
 | 
	
		
			
				|  |  | +    laNotifyUsers("la.animation.current_action");
 | 
	
		
			
				|  |  |      return ak;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -168,6 +171,7 @@ void la_AnimationEvaluateActions(){
 | 
	
		
			
				|  |  |  void la_AnimationPreFrame(){
 | 
	
		
			
				|  |  |      if(MAIN.Animation->PlayHead<0){
 | 
	
		
			
				|  |  |          MAIN.Animation->PlayHead=0; laAnimationSetPlayStatus(0);
 | 
	
		
			
				|  |  | +        la_AnimationEvaluateActions();
 | 
	
		
			
				|  |  |          laNotifyUsers("la.animation.play_head");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      if(MAIN.Animation->PlayStatus){
 | 
	
	
		
			
				|  | @@ -184,41 +188,177 @@ void la_AnimationPostFrame(){
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +void laget_AnimationChannelName(laActionChannel *p, char *result, char** here){
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  int LAMOD_AnimationActionsCanvas(laOperator *a, laEvent *e){
 | 
	
		
			
				|  |  |      laUiItem *ui = a->Instance; laBoxedTheme *bt = (*ui->Type->Theme);
 | 
	
		
			
				|  |  |      laCanvasExtra *ex = a->CustomData; laAction* aa=ui->PP.EndInstance;
 | 
	
		
			
				|  |  |      if(!aa) LA_RUNNING_PASS;
 | 
	
		
			
				|  |  | +    int W, H; W = ui->R - ui->L; H = ui->B - ui->U;
 | 
	
		
			
				|  |  | +    int ShowSide=(ex->ShowLegend&&ex->LW<W-2*LA_RH);
 | 
	
		
			
				|  |  | +    int ll=ui->L, lr=ll+(ShowSide?ex->LW:0), tl=lr, tr=ui->R;
 | 
	
		
			
				|  |  | +    int FW=LA_RH/2;
 | 
	
		
			
				|  |  | +    int Channels=aa?lstCountElements(&aa->Channels):0;
 | 
	
		
			
				|  |  | +    int Modal=0; int mid=((W-lr)/2);
 | 
	
		
			
				|  |  | +    
 | 
	
		
			
				|  |  | +    if(e->Type==LA_M_MOUSE_DOWN){
 | 
	
		
			
				|  |  | +        ex->UiMode=1; ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1; ex->Dragging=10;
 | 
	
		
			
				|  |  | +    }elif(e->Type==LA_M_MOUSE_UP || e->Type==LA_L_MOUSE_UP){
 | 
	
		
			
				|  |  | +        ex->UiMode=0; Modal=1; ex->Dragging=0; ex->TargetIndexVali=0;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(ex->UiMode==1){
 | 
	
		
			
				|  |  | +        if(e->Type&LA_MOUSE_EVENT){
 | 
	
		
			
				|  |  | +            ex->PanY-=e->y-ex->ClickedY; ex->PanX-=e->x-ex->ClickedX;
 | 
	
		
			
				|  |  | +            ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }elif(ex->UiMode==2){
 | 
	
		
			
				|  |  | +        if(e->Type&LA_MOUSE_EVENT){
 | 
	
		
			
				|  |  | +            ex->LW=e->x-ui->L+LA_SEAM_W; ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1;
 | 
	
		
			
				|  |  | +            if(ex->LW<LA_RH*3 && ex->LW>=LA_RH/2){ ex->LW=LA_RH*3; }
 | 
	
		
			
				|  |  | +            if(ex->LW<LA_RH/2 && ex->Dragging!=12){ ex->ShowLegend=0; ex->LW=0; }
 | 
	
		
			
				|  |  | +            if(ex->LW<LA_RH*3){ ex->LW=LA_RH*3;}
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    int MaxDN=LA_RH*(Channels+1)-H+bt->TP+bt->BP; if(MaxDN<0) MaxDN=0;
 | 
	
		
			
				|  |  | +    if(!Modal){
 | 
	
		
			
				|  |  | +        if(e->x<=lr){
 | 
	
		
			
				|  |  | +            if(e->Type==LA_MOUSE_WHEEL_DOWN){ ex->PanY+=LA_RH*MAIN.ScrollingSpeed; Modal=1; }
 | 
	
		
			
				|  |  | +            if(e->Type==LA_MOUSE_WHEEL_UP){ ex->PanY-=LA_RH*MAIN.ScrollingSpeed; Modal=1; }
 | 
	
		
			
				|  |  | +            if(e->x>=lr-LA_SEAM_W*2){ if(!ex->TargetIndexVali){ ex->TargetIndexVali=1; Modal=1; }
 | 
	
		
			
				|  |  | +                if(e->Type==LA_L_MOUSE_DOWN){
 | 
	
		
			
				|  |  | +                    ex->UiMode=2; ex->ClickedX=e->x; ex->ClickedY=e->y; Modal=1; ex->Dragging=10; Modal=1;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }else{ if(ex->TargetIndexVali){ ex->TargetIndexVali=0; Modal=1; } }
 | 
	
		
			
				|  |  | +        }else{
 | 
	
		
			
				|  |  | +            if((!ex->ShowLegend)&&e->x<=ll+LA_SEAM_W*2){
 | 
	
		
			
				|  |  | +                if(!ex->TargetIndexVali){ ex->TargetIndexVali=1; Modal=1; }
 | 
	
		
			
				|  |  | +                if(e->Type==LA_L_MOUSE_DOWN){ ex->LW=LA_RH*4; ex->Dragging=12; ex->ShowLegend=1; Modal=1; ex->UiMode=2; ex->TargetIndexVali=1; }
 | 
	
		
			
				|  |  | +            }else{ if(ex->TargetIndexVali){ ex->TargetIndexVali=0; Modal=1; } }
 | 
	
		
			
				|  |  | +            if(e->Type==LA_MOUSE_WHEEL_DOWN){ ex->ZoomX*=0.9; ex->PanX+=mid; ex->PanX*=0.9; ex->PanX-=mid; Modal=1; }
 | 
	
		
			
				|  |  | +            if(e->Type==LA_MOUSE_WHEEL_UP){ ex->ZoomX*=1.1; ex->PanX+=mid; ex->PanX*=1.1; ex->PanX-=mid; Modal=1; }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(ex->PanY>MaxDN){ ex->PanY=MaxDN; } if(ex->PanY<0){ ex->PanY=0; }
 | 
	
		
			
				|  |  | +    if(ex->PanX<0){ ex->PanX=0; }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(ex->TargetIndexVali){ laSetWindowCursor(LA_LEFT_AND_RIGHT); }else{ laSetWindowCursor(LA_ARROW); }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(Modal){ laRedrawCurrentPanel(); return LA_RUNNING; }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      return LA_RUNNING_PASS;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_AnimationActionCanvasInit(laUiItem *ui){
 | 
	
		
			
				|  |  |      la_CanvasInit(ui);
 | 
	
		
			
				|  |  | -    laCanvasExtra* e=ui->Extra; e->LW=LA_RH*7; e->ShowLegend=1;
 | 
	
		
			
				|  |  | +    laCanvasExtra* ex=ui->Extra; ex->LW=LA_RH*7; ex->ShowLegend=1;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  void la_AnimationActionDrawCanvas(laBoxedTheme *bt, laAction *aa, laUiItem* ui){
 | 
	
		
			
				|  |  | -    laCanvasExtra* e=ui->Extra; //laAction* aa=ui->PP.EndInstance;
 | 
	
		
			
				|  |  | +    laCanvasExtra* ex=ui->Extra; //laAction* aa=ui->PP.EndInstance;
 | 
	
		
			
				|  |  |      int W, H; W = ui->R - ui->L; H = ui->B - ui->U; if (W<=0 || H<=0) return;
 | 
	
		
			
				|  |  | -    int ShowSide=(e->ShowLegend&&e->LW<W-2*LA_RH);
 | 
	
		
			
				|  |  | -    int ll=ui->L, lr=ll+(ShowSide?e->LW:0), tl=lr, tr=ui->R;
 | 
	
		
			
				|  |  | +    int ShowSide=(ex->ShowLegend&&ex->LW<W-2*LA_RH);
 | 
	
		
			
				|  |  | +    int ll=ui->L, lr=ll+(ShowSide?ex->LW-1:0), tl=lr, tr=ui->R;
 | 
	
		
			
				|  |  | +    int FW=LA_RH/2;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      //if (!e->OffScr || e->OffScr->pColor[0]->Height != ui->B - ui->U || e->Be.OffScr->pColor[0]->Width != ui->R - ui->L){
 | 
	
		
			
				|  |  |      //    if (e->OffScr) tnsDelete2DOffscreen(e->OffScr);
 | 
	
		
			
				|  |  |      //    e->OffScr = tnsCreate2DOffscreen(GL_RGBA, W, H, MAIN.PanelMultisample, 1, 0);
 | 
	
		
			
				|  |  |      //}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    real *bkg=laThemeColor(bt,LA_BT_NORMAL);
 | 
	
		
			
				|  |  | +    real *txt=laThemeColor(bt,LA_BT_TEXT);
 | 
	
		
			
				|  |  | +    real *act=laThemeColor(bt,LA_BT_ACTIVE);
 | 
	
		
			
				|  |  |      tnsUseNoTexture();
 | 
	
		
			
				|  |  | +    tnsColor4d(LA_COLOR3(bkg),bkg[3]*0.3);
 | 
	
		
			
				|  |  | +    tnsVertex2d(tl, ui->U); tnsVertex2d(tr, ui->U);
 | 
	
		
			
				|  |  | +    tnsVertex2d(tr, ui->B); tnsVertex2d(tl, 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);
 | 
	
		
			
				|  |  | +    int row=1,curframe,cx; real fl,fr;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
 | 
	
		
			
				|  |  | +    tnsVertex2d(ui->L, ui->U+bt->TP+LA_RH); tnsVertex2d(ui->R, ui->U+bt->TP+LA_RH);
 | 
	
		
			
				|  |  | +    tnsVertex2d(ui->R, ui->U); tnsVertex2d(ui->L, ui->U);
 | 
	
		
			
				|  |  | +    tnsPackAs(GL_TRIANGLE_FAN);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    tnsColor4dv(laThemeColor(bt,LA_BT_TEXT));
 | 
	
		
			
				|  |  | +    tnsVertex2d(tl, LA_RH+ui->U); tnsVertex2d(tr, LA_RH+ui->U);
 | 
	
		
			
				|  |  | +    tnsPackAs(GL_LINES);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    tnsFlush();
 | 
	
		
			
				|  |  | +    int sx,sy,sw,sh,vl,vr,vu,vb;
 | 
	
		
			
				|  |  | +    la_DoUiScissor(ui,&sx,&sy,&sw,&sh,&vl,&vr,&vu,&vb);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if(aa){
 | 
	
		
			
				|  |  | +        curframe=LA_ACTION_FRAME(aa); fl=tl+curframe*FW*ex->ZoomX-ex->PanX, fr=tl+(curframe+1)*FW*ex->ZoomX-ex->PanX;
 | 
	
		
			
				|  |  | +        tnsUseNoTexture();
 | 
	
		
			
				|  |  | +        tnsColor4dv(laAccentColor(LA_BT_NORMAL));
 | 
	
		
			
				|  |  | +        tnsVertex2d(fl, ui->U); tnsVertex2d(fr, ui->U);
 | 
	
		
			
				|  |  | +        tnsVertex2d(fr, ui->B); tnsVertex2d(fl, ui->B);
 | 
	
		
			
				|  |  | +        tnsPackAs(GL_TRIANGLE_FAN);
 | 
	
		
			
				|  |  | +        tnsFlush(); glLineWidth(2);
 | 
	
		
			
				|  |  | +        for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
 | 
	
		
			
				|  |  | +            real ku=ui->U+bt->TP+row*LA_RH-ex->PanY,kb=ku+LA_RH;
 | 
	
		
			
				|  |  | +            for(laActionKey* ak=ac->Keys.pFirst;ak;ak=ak->Item.pNext){
 | 
	
		
			
				|  |  | +                real kl=tl+ak->At*FW*ex->ZoomX-ex->PanX, kr=tl+(ak->At+1)*FW*ex->ZoomX-ex->PanX;
 | 
	
		
			
				|  |  | +                if(curframe==ak->At) tnsColor4d(LA_COLOR3(txt),txt[3]*0.6);
 | 
	
		
			
				|  |  | +                else tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE));
 | 
	
		
			
				|  |  | +                tnsVertex2d(kl, ku); tnsVertex2d(kr, ku);
 | 
	
		
			
				|  |  | +                tnsVertex2d(kr, kb); tnsVertex2d(kl, kb);
 | 
	
		
			
				|  |  | +                tnsPackAs(GL_TRIANGLE_FAN);
 | 
	
		
			
				|  |  | +                tnsColor4dv(laThemeColor(bt,LA_BT_TEXT_ACTIVE));
 | 
	
		
			
				|  |  | +                tnsVertex2d(kl, ku); tnsVertex2d(kr, ku);
 | 
	
		
			
				|  |  | +                tnsVertex2d(kr, kb); tnsVertex2d(kl, kb);
 | 
	
		
			
				|  |  | +                tnsPackAs(GL_LINE_LOOP);
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            row++;
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        tnsFlush(); glLineWidth(1);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE));
 | 
	
		
			
				|  |  | +        cx=tl+aa->PlayHead*aa->FrameCount*FW*ex->ZoomX-ex->PanX; tnsVertex2d(cx, ui->U); tnsVertex2d(cx, ui->B);
 | 
	
		
			
				|  |  | +        tnsPackAs(GL_LINES); glLineWidth(3); tnsFlush(); glLineWidth(1);
 | 
	
		
			
				|  |  | +        tnsColor4dv(laAccentColor(LA_BT_TEXT_ACTIVE));
 | 
	
		
			
				|  |  | +        tnsVertex2d(cx, ui->U+LA_RH); tnsVertex2d(cx+LA_RH, ui->U+LA_RH);
 | 
	
		
			
				|  |  | +        tnsVertex2d(cx+LA_RH, ui->U); tnsVertex2d(cx, ui->U);
 | 
	
		
			
				|  |  | +        tnsPackAs(GL_TRIANGLE_FAN);
 | 
	
		
			
				|  |  | +        char buf[32]; sprintf(buf,"%d",curframe);
 | 
	
		
			
				|  |  | +        tnsDrawStringAuto(buf,laThemeColor(bt,LA_BT_TEXT_ACTIVE),cx+bt->LP,cx+LA_RH*2,ui->U+bt->TP,0);
 | 
	
		
			
				|  |  | +        tnsPackAs(GL_TRIANGLE_FAN); tnsUseNoTexture();
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if(ShowSide){
 | 
	
		
			
				|  |  |          tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL));
 | 
	
		
			
				|  |  |          tnsVertex2d(ll, ui->U); tnsVertex2d(lr, ui->U);
 | 
	
		
			
				|  |  |          tnsVertex2d(lr, ui->B); tnsVertex2d(ll, ui->B);
 | 
	
		
			
				|  |  |          tnsPackAs(GL_TRIANGLE_FAN);
 | 
	
		
			
				|  |  | +        if(!aa){
 | 
	
		
			
				|  |  | +            tnsDrawStringAuto("No action selected",laThemeColor(bt,LA_BT_TEXT),ll+bt->LP,lr-bt->RP,ui->U+bt->BP,0);
 | 
	
		
			
				|  |  | +        }else{ int row=1;
 | 
	
		
			
				|  |  | +            for(laActionChannel* ac=aa->Channels.pFirst;ac;ac=ac->Item.pNext){
 | 
	
		
			
				|  |  | +                tnsDrawStringAuto(ac->CachedName->Ptr,laThemeColor(bt,LA_BT_TEXT),ll+bt->LP,lr-bt->RP,ui->U+bt->TP+row*LA_RH-ex->PanY,0);
 | 
	
		
			
				|  |  | +                row++;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +    if(ex->TargetIndexVali==1){
 | 
	
		
			
				|  |  | +        int LR=TNS_MAX2(lr,ui->L+LA_SEAM_W*2);
 | 
	
		
			
				|  |  | +        tnsColor4dv(act);tnsUseNoTexture();
 | 
	
		
			
				|  |  | +        tnsVertex2d(LR, ui->B); tnsVertex2d(LR-LA_SEAM_W*2, ui->B);
 | 
	
		
			
				|  |  | +        tnsVertex2d(LR-LA_SEAM_W*2, ui->U); tnsVertex2d(LR, ui->U);
 | 
	
		
			
				|  |  | +        tnsPackAs(GL_TRIANGLE_FAN);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    tnsFlush();
 | 
	
		
			
				|  |  | +    tnsViewportWithScissor(sx,sy,sw,sh);
 | 
	
		
			
				|  |  | +    tnsOrtho(vl,vr,vb,vu,-100,100);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    tnsUseNoTexture();
 | 
	
		
			
				|  |  | +    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_AnimationActionDrawOverlay(laUiItem *ui, int h){
 | 
	
		
			
				|  |  |      laCanvasExtra *e = ui->Extra; laBoxedTheme *bt = (*ui->Type->Theme);
 |