*/}}
Browse Source

Compound meter type2

YimingWu 3 months ago
parent
commit
4bf7730b29
8 changed files with 264 additions and 23 deletions
  1. 1 1
      la_controllers.c
  2. 4 2
      la_interface.h
  3. 2 1
      la_resource.c
  4. 12 0
      la_tns.h
  5. 44 6
      la_tns_kernel.c
  6. 3 3
      resources/la_nodes_basic.c
  7. 3 3
      resources/la_templates.c
  8. 195 7
      resources/la_widgets.c

+ 1 - 1
la_controllers.c

@@ -172,7 +172,7 @@ void la_AddButtonProp(laPropContainer* pc, char* id, char* name, char* desc, int
     p->ElementBytes=1;
 }
 void la_AddAxisProp(laPropContainer* pc, char* id, char* name, char* id_min, char* id_max, char* id_cmin, char* id_cmax, char* desc, int i, int array_len, char* array_prefix){
-    laProp* p=laAddIntProperty(pc,id,name,desc,array_len>1?LA_WIDGET_VALUE_METER_2D:LA_WIDGET_VALUE_METER,
+    laProp* p=laAddIntProperty(pc,id,name,desc,array_len>1?LA_WIDGET_VALUE_METER_2D:LA_WIDGET_METER_TYPE2,
         array_prefix,0,32767,-32768,1,0,0,offsetof(laController, AxisValues[i]),0,0,array_len,0,0,0,0,0,0,0,LA_READ_ONLY);
     if(id_min) p=laAddIntProperty(pc,id_min,id_min,desc,0,
         array_prefix,0,32767,-32768,1,0,0,offsetof(laController, AxisLimitMins[i]),0,0,array_len,0,0,0,0,0,0,0,0);

+ 4 - 2
la_interface.h

@@ -1148,7 +1148,8 @@ 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_VALUE_METER;
+extern laWidget* LA_WIDGET_METER_TYPE1;
+extern laWidget* LA_WIDGET_METER_TYPE2;
 extern laWidget* LA_WIDGET_VALUE_METER_2D;
 extern laWidget* LA_WIDGET_FLOAT;
 extern laWidget* LA_WIDGET_FLOAT_PLAIN;
@@ -2395,7 +2396,8 @@ 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_VALUE_METER;
+extern laUiType *_LA_UI_METER_TYPE1;
+extern laUiType *_LA_UI_METER_TYPE2;
 extern laUiType *_LA_UI_VALUE_METER_2D;
 extern laUiType *_LA_UI_FLOAT;
 extern laUiType *_LA_UI_FLOAT_COLOR;

+ 2 - 1
la_resource.c

@@ -37,7 +37,8 @@ laUiType *_LA_UI_COLLECTION_SINGLE;
 laUiType *_LA_UI_BUTTON;
 laUiType *_LA_UI_LABEL;
 laUiType *_LA_UI_INT;
-laUiType *_LA_UI_VALUE_METER;
+laUiType *_LA_UI_METER_TYPE1;
+laUiType *_LA_UI_METER_TYPE2;
 laUiType *_LA_UI_VALUE_METER_2D;
 laUiType *_LA_UI_FLOAT;
 laUiType *_LA_UI_FLOAT_COLOR;

+ 12 - 0
la_tns.h

@@ -414,6 +414,12 @@ struct _tnsFont
     int CurrentY;
 };
 
+typedef struct _tnsStringClip tnsStringClip;
+struct _tnsStringClip{
+    laListItem Item;
+    int L,R,U,B;
+};
+
 typedef struct _tnsFontManager tnsFontManager;
 struct _tnsFontManager
 {
@@ -425,6 +431,9 @@ struct _tnsFontManager
     int BufferWidth;
 
     unsigned LastDlst;
+
+    laListHandle StringClips;
+    int L,R,U,B;
 };
 
 typedef struct _tnsFontBoundBox tnsFontBoundBox;
@@ -1393,6 +1402,9 @@ int laStopFontService();
 
 void tfntResizeFontTexture(tnsFont* f, int size);
 
+void tnsPushStringClip(int L, int R, int U, int B);
+void tnsPopStringClip();
+
 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);

+ 44 - 6
la_tns_kernel.c

@@ -2627,6 +2627,7 @@ tnsFontManager *FM;
 void tnsSetuptnsFontManager(){
     FM = CreateNew(tnsFontManager);
     FM->BufferWidth = TNS_FONT_BUFFER_W_DEFAULT;
+    FM->L = INT_MIN; FM->R = INT_MAX; FM->B = INT_MAX; FM->U = INT_MIN;
 };
 void tnsQuitFontManager(){
     tnsInvalidateFontCache();
@@ -2880,6 +2881,17 @@ int CMP_NAME_IsThisFont(tnsFont *enumed, char *name){
     return (!strcmp(enumed->fontName, name));
 };
 
+void tnsPushStringClip(int L, int R, int U, int B){
+    tnsStringClip *sc=memAcquire(sizeof(tnsStringClip)); lstPushItem(&FM->StringClips, sc);
+    sc->L=FM->L; sc->R=FM->R; sc->U=FM->U; sc->B=FM->B;
+    FM->L=L; FM->R=R; FM->U=U; FM->B=B;
+}
+void tnsPopStringClip(){
+    tnsStringClip *sc=lstPopItem(&FM->StringClips);
+    if(!sc){ FM->L = INT_MIN; FM->R = INT_MAX; FM->B = INT_MAX; FM->U = INT_MIN; }
+    FM->L=sc->L; FM->R=sc->R; FM->U=sc->U; FM->B=sc->B;
+};
+
 int tnsStringGetDimension(char* content, uint32_t* contentU, int Count, int WLimit, int* Rows, int UseMono){
     if((!MAIN.CurrentWindow)||(!MAIN.CurrentWindow->win)) return 0;
     real sx = 0; int sy = FM->UsingFont->height; real MA=FM->UsingFont->MonoAdvance;
@@ -3017,6 +3029,31 @@ void tnsDrawStringLCD(char *content, uint32_t* contentU, real Color[4], int L, i
     }
     if(any){ tnsColor4dv(Color); tnsPackAs(GL_LINES); }
 }
+
+    //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;
+int tns_ClipCharacterT2D(real* v, real* t){
+    real l=v[0]; if(l>FM->R) return 0; real r=v[4]; if(r<FM->L) return 0;
+    real u=v[1]; if(u>FM->B) return 0; real b=v[3]; if(b<FM->U) return 0;
+    real tl=t[0],tr=t[4],tu=t[1],tb=t[3];
+    if(l<FM->L){ real p=((real)FM->L-l)/(r-l); t[0]+=p*(tr-tl); t[6]=t[2]=t[0]; v[6]=v[2]=v[0]=FM->L; }
+    if(r>FM->R){ real p=(r-(real)FM->R)/(r-l); t[4]-=p*(tr-tl); t[8]=t[10]=t[4]; v[8]=v[10]=v[4]=FM->R; }
+    if(u<FM->U){ real p=((real)FM->U-u)/(b-u); t[1]+=p*(tb-tu); t[5]=t[9]=t[1]; v[5]=v[9]=v[1]=FM->U; }
+    if(b>FM->B){ real p=(b-(real)FM->B)/(b-u); t[3]-=p*(tb-tu); t[7]=t[11]=t[3]; v[7]=v[11]=v[3]=FM->B; }
+    return 1;
+}
 void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int R, int T, int Flags){
     if(Flags&(LA_TEXT_LCD_16|LA_TEXT_LCD_7)){
         tnsDrawStringLCD(content,contentU,Color,L,R,T,Flags,1.0); return;
@@ -3075,14 +3112,15 @@ void tnsDrawStringM(char *content, uint32_t* contentU, real Color[4], int L, int
                           cx, +cy,
                           cx + fsc->width, +cy - fsc->height,
                           cx + fsc->width, +cy);
-
-        tnsUseMaskTexture(&f->TexBuffer);
-        tnsVertexArray2d(VertArr, 6);
-        tnsTexCoordArray2d(TexCoord, 6);
-        any=1;
+        
+        if(tns_ClipCharacterT2D(VertArr,TexCoord)){
+            tnsUseMaskTexture(&f->TexBuffer);
+            tnsVertexArray2d(VertArr, 6);
+            tnsTexCoordArray2d(TexCoord, 6);
+            any=1;
+        }
 
         sx += dx;
-        
         if(BreakNow){ break; }
     }
     if(any) tnsPackAs(GL_TRIANGLES);

+ 3 - 3
resources/la_nodes_basic.c

@@ -1255,8 +1255,8 @@ void la_RegisterInputMapperOperators(){
 
     pc=laAddPropertyContainer("la_input_controller_node_socket", "Controller Socket", "One value from a controller output",0,0,sizeof(laInputControllerNodeSocket),0,0,1|LA_PROP_OTHER_ALLOC);
     laAddStringProperty(pc,"which","Which","Select which output from the controller",0,0,0,0,1,offsetof(laInputControllerNodeSocket,Which),0,0,laset_InputControllerNodeSocketWhich,0,LA_AS_IDENTIFIER);
-    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
-    laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_METER_TYPE1,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_METER_TYPE1,0,0,1,-1,0,0,0,offsetof(laInputControllerNodeSocket,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     p=laAddEnumProperty(pc,"switch", "SW", "Switch value", LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(laInputControllerNodeSocket,IntVal),0,0,0,laget_SocketEnumArrayLength,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     laAddEnumItemAs(p,"IDLE", "Idle", "Button is not pressed", 0, 0);
     laAddEnumItemAs(p,"ACTIVE", "Active", "Button is pressed", 1, 0);
@@ -1266,7 +1266,7 @@ void la_RegisterInputMapperOperators(){
     LA_PC_IDN_VISUALIZER=pc; laPropContainerExtraFunctions(pc,0,0,0,0,laui_DefaultNodeOperationsPropUiDefine);
     laAddSubGroup(pc,"base","Base","Base node","la_base_node",0,0,0,0,0,0,0,0,0,0,0,LA_UDF_LOCAL);
     laAddSubGroup(pc, "in", "In","Input value","la_in_socket",0,0,0,offsetof(laInputVisualizerNode,In),0,0,0,0,0,0,0,LA_UDF_SINGLE);
-    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_VALUE_METER,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
+    laAddFloatProperty(pc,"axis", "🡘", "Axis value", LA_WIDGET_METER_TYPE1,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,0,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     laAddFloatProperty(pc,"axis2d", "2D Axis", "2D Axis value", LA_WIDGET_VALUE_METER_2D,0,0,1,-1,0,0,0,offsetof(laInputVisualizerNode,RealVal),0,0,2,0,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     p=laAddEnumProperty(pc,"switch", "SW", "Switch value", LA_WIDGET_ENUM_HIGHLIGHT,0,0,0,0,offsetof(laInputVisualizerNode,IntVal),0,0,0,laget_VisualizerArrayLength,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE);
     laAddEnumItemAs(p,"IDLE", "Idle", "Button is not pressed", 0, 0);

+ 3 - 3
resources/la_templates.c

@@ -1687,7 +1687,7 @@ void laui_AnimationActionSimple(laUiList *uil, laPropPack *This, laPropPack *Ext
         }laElse(uil,b2);{
             laShowLabel(uil,c,"  ",0,0)->Flags|=LA_TEXT_MONO;
         }laEndCondition(uil,b2);
-        laUiItem* ui=laShowItemFull(uil,c,This,"play_head",LA_WIDGET_VALUE_METER,0,0,0);
+        laUiItem* ui=laShowItemFull(uil,c,This,"play_head",LA_WIDGET_METER_TYPE1,0,0,0);
         ui->Flags|=LA_UI_FLAGS_NO_LABEL|LA_UI_FLAGS_UNDERNEATH; ui->Expand=1;
         laShowItem(uil,c,This,"name")->Flags|=LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_NO_EVENT;
         laShowItemFull(uil,c,This,"solo",0,"icon=S;",0,0)->Flags=LA_UI_FLAGS_ICON|LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_HIGHLIGHT;
@@ -1704,7 +1704,7 @@ void laui_AnimationActionListItem(laUiList *uil, laPropPack *This, laPropPack *E
     laColumn* c=laFirstColumn(uil); laUiItem* ui;
     laUiItem* b=laBeginRow(uil,c,0,0);{
         //laUiItem* b2=laOnConditionThat(uil,c,laNot(laEqual(laPropExpression(This,"__self"),laPropExpression(0,"la.animation.current_action"))));{
-        //    ui=laShowItemFull(uil,c,This,"play_head",LA_WIDGET_VALUE_METER,0,0,0);
+        //    ui=laShowItemFull(uil,c,This,"play_head",LA_WIDGET_METER_TYPE1,0,0,0);
         //    ui->Flags|=LA_UI_FLAGS_NO_LABEL|LA_UI_FLAGS_UNDERNEATH; ui->Expand=1;
         //}laEndCondition(uil,b2);
         ui=laShowItem(uil,c,This,"name");
@@ -1766,7 +1766,7 @@ void laui_AnimationActionChannels(laUiList *uil, laPropPack *This, laPropPack *E
     b2=laOnConditionThat(uil,c,laPropExpression(0,"la.animation.current_action"));{
         laUiItem* ca=laShowInvisibleItem(uil,c,0,"la.animation.current_action");
         row=laBeginRow(uil,crl,0,0);
-        ui=laShowItemFull(uil,crl,&ca->PP,"play_head",LA_WIDGET_VALUE_METER,0,0,0);
+        ui=laShowItemFull(uil,crl,&ca->PP,"play_head",LA_WIDGET_METER_TYPE1,0,0,0);
         ui->Flags|=LA_UI_FLAGS_NO_LABEL|LA_UI_FLAGS_UNDERNEATH; ui->Expand=1;
         laShowItem(uil,crl,&ca->PP,"current_frame")->Flags|=LA_UI_FLAGS_NO_LABEL|LA_UI_FLAGS_NO_DECAL|LA_TEXT_ALIGN_CENTER;
         laShowSeparator(uil,crl);

+ 195 - 7
resources/la_widgets.c

@@ -36,7 +36,8 @@ 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_VALUE_METER={0,LA_TEXT_ALIGN_CENTER};
+laWidget _LA_WIDGET_METER_TYPE1={0,LA_TEXT_ALIGN_CENTER};
+laWidget _LA_WIDGET_METER_TYPE2={0,LA_TEXT_ALIGN_CENTER};
 laWidget _LA_WIDGET_VALUE_METER_2D={0,LA_TEXT_ALIGN_CENTER};
 laWidget _LA_WIDGET_FLOAT={0};
 laWidget _LA_WIDGET_FLOAT_PLAIN={0, LA_UI_FLAGS_PLAIN};
@@ -79,7 +80,8 @@ 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_VALUE_METER=&_LA_WIDGET_VALUE_METER;
+laWidget *LA_WIDGET_METER_TYPE1=&_LA_WIDGET_METER_TYPE1;
+laWidget *LA_WIDGET_METER_TYPE2=&_LA_WIDGET_METER_TYPE2;
 laWidget *LA_WIDGET_VALUE_METER_2D=&_LA_WIDGET_VALUE_METER_2D;
 laWidget *LA_WIDGET_FLOAT=&_LA_WIDGET_FLOAT;
 laWidget *LA_WIDGET_FLOAT_PLAIN=&_LA_WIDGET_FLOAT_PLAIN;
@@ -1482,7 +1484,7 @@ void la_ImageDraw(laUiItem *ui, int h){
     tnsFlush();
 }
 
-void la_ValueMeterDraw(laUiItem *ui, int h){
+void la_ValueMeterType1Draw(laUiItem *ui, int h){
     laBoxedTheme *bt = (*ui->Type->Theme);
     int DataI[8]; real Data[8];
     int Len, i, W; real Seg;
@@ -1599,6 +1601,185 @@ void la_ValueMeterDraw(laUiItem *ui, int h){
 
     tnsFlush();
 }
+void la_ValueMeterType2Draw(laUiItem *ui, int h){
+    laBoxedTheme *bt = (*ui->Type->Theme);
+    int DataI[8]; real Data[8]; int SDataI[8]; real SData[8]; int Len, i, W; real Seg;
+    char buf[48] = {0}; char buf2[48] = {0};char prefix[16][64] = {0};char limits[2][64]={0};
+    int Original;
+    int Imin=-100, Imax=100; real min=-100, max=100;
+    int s, State; int IsVertical=ui->Flags&LA_UI_FLAGS_TRANSPOSE;
+    int NoLabel=ui->Flags&LA_UI_FLAGS_NO_LABEL;
+
+    int IsInt=(ui->PP.LastPs->p->PropertyType&LA_PROP_INT)?1:0;
+    Len = laGetArrayLength(&ui->PP);
+    laGetPrefixP(&ui->PP, prefix);
+    if(IsInt){
+        laGetIntArray(&ui->PP, DataI); for(int i=0;i<Len;i++){ Data[i]=DataI[i]; }
+        laGetIntRange(&ui->PP, &Imin, &Imax); min=Imin; max=Imax;
+        sprintf(limits[0],"%d",Imin); sprintf(limits[1],"%d",Imax);
+    }else{
+        laGetFloatArray(&ui->PP, Data);
+        laGetFloatRange(&ui->PP,&min,&max);
+        sprintf(limits[0],"%lf",min); sprintf(limits[1],"%lf",max);
+    }
+
+    int sl = TNS_MAX2(abs(ui->SymbolID),5);
+    int ScaleLen = sl * LA_RH;
+    real seg = abs(ui->TemplateContext)/100;
+    int times=1,times10=0;
+    while((max-min)/seg > ScaleLen/10){
+        seg*=10;
+    }
+    if(seg>100){ int sseg=seg; while(sseg>=100){ sseg/=10; times*=10; times10++; } }
+
+    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;
+        }
+
+        real cx=(_L+_R)/2,cy=(_U+_B)/2,cw=(_R-_L),ch=(_B-_U);
+        
+        tnsPushStringClip(_L,_R,_U,_B);
+
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,ui->State));
+        tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+        tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        int oflow=0,ofhigh=0;
+        if(Data[i]<min){ oflow=1; Data[i]=min; }
+        if(Data[i]>max){ ofhigh=1; Data[i]=max; }
+        
+        real fac = (real)(Data[i]-min) / (real)(max - min);
+        int SL,SR,SU,SB,_SL,_SR,_SU,_SB,Move = fac*ScaleLen;
+        if(IsVertical){ SL=_L; SR=_R; SB=_SB=cy+Move; SU=_SU=SB-ScaleLen; TNS_CLAMP(SB,_U,_B); TNS_CLAMP(SU,_U,_B); }
+        else{ SL=_SL=cx-Move; SR=_SR=SL+ScaleLen; SB=_B; SU=_U; TNS_CLAMP(SL,_L,_R); TNS_CLAMP(SR,_L,_R); }
+        tnsUseNoTexture(); real* color=laThemeColor(bt,LA_BT_TEXT);
+        tnsColor4d(LA_COLOR3(color),0.3);
+        tnsVertex2d(SL, SU); tnsVertex2d(SR, SU);
+        tnsVertex2d(SR, SB); tnsVertex2d(SL, SB);
+        tnsPackAs(GL_TRIANGLE_FAN);
+
+        tnsColor4d(LA_COLOR3(color),0.7);
+        int scalelow=min/seg-1, scalehigh=max/seg+1;
+        for(int si=scalelow;si<=scalehigh;si++){
+            for(int ssi=0;ssi<10;ssi++){
+                real val=si*seg + ssi*0.1*seg; if(val<min) continue; if(val>max) break;
+                real sfac = (real)(val-min) / (max - min); int smove=Move-sfac*ScaleLen;
+                real lfac = ssi==0?(si==ssi?0.5:0.3):(ssi==5?0.2:0.1);
+                if(IsVertical){ int scaleb=cy+smove; if(scaleb>_B || scaleb<_U) continue;
+                    tnsVertex2d(cx-cw*lfac,scaleb); tnsVertex2d(cx+cw*lfac,scaleb);
+                }else{ int scalel=cx-smove; if(scalel<_L || scalel>_R) continue;
+                    tnsVertex2d(scalel,cy+ch*lfac); tnsVertex2d(scalel,cy-ch*lfac);
+                }
+            }
+        }
+        tnsPackAs(GL_LINES);
+
+        if(!NoLabel){
+            for(int si=scalelow;si<=scalehigh;si++){
+                real val=si*seg; if(val<min) continue; if(val>max) break;
+                real sfac = (real)(val-min) / (max - min); int smove=Move-sfac*ScaleLen;
+                    if(IsInt) sprintf(buf,"%.0lf",val/times); else sprintf(buf,"%.2lf",val/times);
+                if(IsVertical){ int scaleb=cy+smove; if(scaleb>_B+LA_RH2 || scaleb<_U-LA_RH2) continue;
+                    tnsDrawStringAuto(buf,laThemeColor(bt,LA_BT_TEXT),_L+bt->LM,_R-bt->RM,scaleb-LA_RH2,ui->Flags);
+                }else{ int scalel=cx-smove; if(scalel<_L-100 || scalel>_R+100) continue;
+                    tnsDrawStringAuto(buf,laThemeColor(bt,LA_BT_TEXT),scalel-100,scalel+100,_U,ui->Flags);
+                }
+            }
+            if(IsVertical){
+                tnsDrawStringAuto(limits[0],laThemeColor(bt,LA_BT_TEXT|ui->State),_L+bt->LM,_R-bt->RM,_SB,ui->Flags);
+                tnsDrawStringAuto(limits[1],laThemeColor(bt,LA_BT_TEXT|ui->State),_L+bt->LM,_R-bt->RM,_SU-LA_RH,ui->Flags);
+            }else{
+                tnsDrawStringAuto(limits[0],laThemeColor(bt,LA_BT_TEXT|ui->State),_SL-100,_SL-bt->LM,_B-LA_RH,LA_TEXT_ALIGN_RIGHT);
+                tnsDrawStringAuto(limits[1],laThemeColor(bt,LA_BT_TEXT|ui->State),_SR+bt->RM,_SR+100,_B-LA_RH,LA_TEXT_ALIGN_LEFT);
+            }
+        }
+
+        tnsUseNoTexture();
+        tnsColor4dv(laAccentColor(LA_BT_BORDER));
+        if(IsVertical){tnsVertex2d(_L,cy); tnsVertex2d(_R,cy);}
+        else{tnsVertex2d(cx,_U); tnsVertex2d(cx,_B);}
+        tnsPackAs(GL_LINES);
+
+        if(times!=1){ sprintf(buf,"%d",times10);
+            if(IsVertical && cw>LA_RH) tnsDrawStringAuto(buf,laAccentColor(LA_BT_BORDER),_L+bt->LM,_R-bt->RM,cy,LA_TEXT_MONO|LA_TEXT_ALIGN_RIGHT);
+            elif(ch>LA_RH) tnsDrawStringAuto(buf,laAccentColor(LA_BT_BORDER),cx+bt->LM,cx+100,_U,LA_TEXT_MONO|LA_TEXT_ALIGN_LEFT);
+        }
+
+        tnsUseNoTexture();
+        tnsColor4dv(laThemeColor(bt,LA_BT_BORDER));
+        tnsVertex2d(_L, _U); tnsVertex2d(_R, _U);
+        tnsVertex2d(_R, _B); tnsVertex2d(_L, _B);
+        tnsPackAs(GL_LINE_LOOP);
+
+        //if(IsVertical){
+        //    if(oflow){ tnsDrawStringAuto("⯆",laThemeColor(bt, LA_BT_TEXT), _L+bt->LM,_R-bt->RM, _U, LA_TEXT_ALIGN_CENTER); }
+        //    elif(ofhigh){ tnsDrawStringAuto("⯅",laThemeColor(bt, LA_BT_TEXT), _L+bt->LM,_R-bt->RM, _B-LA_RH, LA_TEXT_ALIGN_CENTER); }
+        //}else{
+        //    if(oflow){ tnsDrawStringAuto("⯇",laThemeColor(bt, LA_BT_TEXT), _L+bt->LM,_R-bt->RM, _U, LA_TEXT_ALIGN_LEFT); }
+        //    elif(ofhigh){ tnsDrawStringAuto("⯈",laThemeColor(bt, LA_BT_TEXT), _L+bt->LM,_R-bt->RM, _U, LA_TEXT_ALIGN_RIGHT); }
+        //}
+
+        tnsPopStringClip();
+    }
+
+    int trisize=LA_RH/3.0f;
+    for(laCompoundPP* CPP=ui->CompoundPPs.pFirst;CPP;CPP=CPP->Item.pNext){
+        IsInt=(CPP->PP.LastPs->p->PropertyType&LA_PROP_INT)?1:0;
+        Len = laGetArrayLength(&CPP->PP);
+        laGetPrefixP(&CPP->PP, prefix);
+        if(IsInt){
+            laGetIntArray(&CPP->PP, SDataI); for(int i=0;i<Len;i++){ SData[i]=SDataI[i]; }
+            //laGetIntRange(&CPP->PP, &Imin, &Imax); min=Imin; max=Imax;
+        }else{
+            laGetFloatArray(&CPP->PP, SData);
+            //laGetFloatRange(&CPP->PP,&min,&max);
+        }
+        if(CPP->Slot <= LA_SLOT_MARKER_4){
+            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;
+                }
+                real cx=(_L+_R)/2,cy=(_U+_B)/2,cw=(_R-_L),ch=(_B-_U);
+                real sfac = (real)(SData[i]-min) / (real)(max - min);
+                real fac = (real)(Data[i]-min) / (real)(max - min);
+                int SL,SR,SU,SB,_SL,_SR,_SU,_SB, Move = fac*ScaleLen,SMove=sfac*ScaleLen;
+                if(IsVertical){ _SB=SB=cy+Move-SMove; TNS_CLAMP(SB,_U,_B); }
+                else{ SL=_SL=cx-Move+SMove; TNS_CLAMP(SL,_L,_R); }
+                
+                tnsUseNoTexture();
+                tnsColor4dv(laThemeColor(bt,LA_BT_TEXT|LA_BT_ACTIVE));
+                if(IsVertical){ tnsVertex2d(_L, SB); tnsVertex2d(_R, SB); }
+                else{ tnsVertex2d(SL, _U); tnsVertex2d(SL, _B); }
+                tnsPackAs(GL_LINES);
+                if(IsVertical){
+                    if(! CPP->Slot % 2){ tnsVertex2d(_L, SB); tnsVertex2d(_L+trisize, SB); tnsVertex2d(_L, SB-trisize); }
+                    else{ tnsVertex2d(_R, SB+trisize); tnsVertex2d(_R-trisize, SB); tnsVertex2d(_R, SB); }
+                    if(SB==_SB){ tnsPackAs(GL_TRIANGLES); }else{ tnsPackAs(GL_LINE_LOOP); }
+                }
+                else{
+                    if(! CPP->Slot % 2){ tnsVertex2d(SL, _B); tnsVertex2d(SL, _B-trisize); tnsVertex2d(SL+trisize, _B); }
+                    else{ tnsVertex2d(SL-trisize, _U); tnsVertex2d(SL, _U+trisize); tnsVertex2d(SL, _U); }
+                    if(SL==_SL){ tnsPackAs(GL_TRIANGLES); }else{ tnsPackAs(GL_LINE_LOOP); }
+                }
+            }
+        }
+    }
+
+    tnsFlush();
+}
 void la_ValueMeter2DDraw(laUiItem *ui, int h){
     laBoxedTheme *bt = (*ui->Type->Theme);
     int DataI[8]; real Data[8];
@@ -1770,6 +1951,9 @@ void la_ImageUiDestroy(laUiItem *ui){
     tnsStopUsingImage(im);
 #endif
 }
+void la_MeterUiInit(laUiItem *ui){
+    la_GeneralUiInit(ui); ui->SymbolID = 20; ui->TemplateContext = 1000;
+}
 
 void la_RegisterUiTypesBasic(){
     laKeyMapper* km;
@@ -1780,12 +1964,16 @@ void la_RegisterUiTypesBasic(){
                         &_LA_THEME_VALUATOR, la_IntDraw, la_ValueGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
     _LA_UI_INT->GetMinWidth=la_ValueGetMinWidth;
 
-    LA_WIDGET_VALUE_METER->Type=
-    _LA_UI_VALUE_METER = la_RegisterUiType("LA_value_meter", 0, 0, &_LA_THEME_VALUATOR, la_ValueMeterDraw, la_ValueMeterGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
-    _LA_UI_VALUE_METER->GetMinWidth=la_ValueGetMinWidth;
+    LA_WIDGET_METER_TYPE1->Type=
+    _LA_UI_METER_TYPE1 = la_RegisterUiType("LA_meter_type1", 0, 0, &_LA_THEME_VALUATOR, la_ValueMeterType1Draw, la_ValueMeterGetHeight, la_MeterUiInit, la_GeneralUiDestroy);
+    _LA_UI_METER_TYPE1->GetMinWidth=la_ValueGetMinWidth;
+
+    LA_WIDGET_METER_TYPE2->Type=
+    _LA_UI_METER_TYPE2 = la_RegisterUiType("LA_meter_type2", 0, 0, &_LA_THEME_VALUATOR, la_ValueMeterType2Draw, la_ValueMeterGetHeight, la_MeterUiInit, la_GeneralUiDestroy);
+    _LA_UI_METER_TYPE2->GetMinWidth=la_ValueGetMinWidth;
     
     LA_WIDGET_VALUE_METER_2D->Type=
-    _LA_UI_VALUE_METER_2D = la_RegisterUiType("LA_value_meter_2d", 0, 0, &_LA_THEME_VALUATOR, la_ValueMeter2DDraw, la_ValueMeter2DGetHeight, la_GeneralUiInit, la_GeneralUiDestroy);
+    _LA_UI_VALUE_METER_2D = la_RegisterUiType("LA_value_meter_2d", 0, 0, &_LA_THEME_VALUATOR, la_ValueMeter2DDraw, la_ValueMeter2DGetHeight, la_MeterUiInit, 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",