*/}}
Explorar el Código

Theme selector and r/w

YimingWu hace 3 meses
padre
commit
bdad4b5ebb

+ 1 - 1
la_controllers.c

@@ -272,7 +272,7 @@ int OPINV_RefreshControllers(laOperator* a, laEvent* e){
 }
 int OPINV_RemoveController(laOperator* a, laEvent* e){
     if(!a->This || !a->This->EndInstance) return LA_FINISHED;
-    laEnableYesNoPanel(0, 0, "Confirm?", "Will remove this controller config.", e->x-200, e->y, 200, e);
+    laEnableYesNoPanel(a, 0, "Confirm?", "Will remove this controller config.", e->x-200, e->y, 200, e);
     return LA_RUNNING;
 }
 int OPMOD_RemoveController(laOperator* a, laEvent* e){

+ 24 - 16
la_data.c

@@ -60,27 +60,35 @@ laPropContainer *la_ContainerLookup(const char *ID){
     return pc;
 }
 
-void la_CopyPropPack(laPropPack* From, laPropPack* To) {
-	laPropStep* ps,*fps,*LastPs=0;
-	To->RawThis = From->RawThis;
-	To->EndInstance = From->EndInstance;
-
-	la_FreePropStepCache(To->Go);
-	To->Go = To->LastPs = 0;
-
-	for (fps = From->Go; fps; fps = fps->pNext) {
+void la_CopyPropStepRecursive(laPropPack* From, laPropPack* To){
+    if(From->RawThis){ la_CopyPropStepRecursive(From->RawThis,To); }
+    laPropStep *ps,*fps,*LastPs=To->LastPs;
+    for (fps = From->Go; fps; fps = fps->pNext) {
 		ps = memAcquireSimple(sizeof(laPropStep));
 		ps->p = fps->p;
 		ps->UseInstance = fps->UseInstance;
 		ps->Type = fps->Type;
-		if (LastPs)LastPs->pNext = ps;
-		else {
-			To->Go = ps;
-		}
+		if (LastPs) LastPs->pNext = ps;
+		else To->Go = ps;
 		LastPs = ps;
 	}
-    if(!LastPs){ To->LastPs = From->LastPs; }
-    else{ To->LastPs =LastPs; }
+    To->LastPs = LastPs;
+}
+void la_CopyPropPack(laPropPack* From, laPropPack* To) {
+	laPropStep* ps,*fps,*LastPs=0;
+	To->EndInstance = From->EndInstance;  
+	To->Go = To->LastPs = 0;
+
+	la_FreePropStepCache(To->Go);
+
+	la_CopyPropStepRecursive(From, To);
+    if(!To->LastPs){
+		ps = memAcquireSimple(sizeof(laPropStep));
+		ps->p = From->LastPs->p;
+		ps->UseInstance = From->LastPs->UseInstance;
+		ps->Type = From->LastPs->Type;
+        To->LastPs = ps;
+    }
 }
 
 laListHandle* laGetUserList(void* HyperUserMem, laProp* Which, int* IsLocal){
@@ -2112,7 +2120,7 @@ int laCanGetCategory(laProp *sub){ laSubProp *sp = sub; if (sub->PropertyType ==
 int laGetUiState(laProp *sub, void *Instance){
     laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetState) return sp->GetState(Instance); } return 0;
 }
-laBoxedTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance){
+laTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance){
     laSubProp *sp = sub; if (sub->PropertyType == LA_PROP_SUB){ if (sp->GetTheme) return sp->GetTheme(parent,Instance); } return 0;
 }
 int laGetUiGap(laProp *sub, void* parent, void *Instance){

+ 2 - 1
la_data.h

@@ -934,6 +934,7 @@ void laRawPropertyExtraFunctions(laProp* p, laRawMultiGetF MultiGet, laRawMultiC
 //void laPropertySignal(laProp* p, int Throw, int Catch);
 
 NEED_STRUCTURE(laBoxedTheme);
+NEED_STRUCTURE(laTheme);
 
 void *laGetInstance(laProp *sub, void *ThisInstance, laPropIterator *pi);
 void *laGetNextInstance(laProp *sub, void *FromInstance, laPropIterator *pi);
@@ -942,7 +943,7 @@ void *laGetActiveInstance(laProp *sub, void *FromInstance, laPropIterator *pi);
 void laSetActiveInstance(laProp *sub, void *FromInstance, void *Instance);
 void laAppendInstance(laSubProp *sub, void *FromInstance, void *Instance);
 int laGetUiState(laProp *sub, void *Instance);
-laBoxedTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance);
+laTheme* laGetUiTheme(laProp *sub, void* parent, void *Instance);
 int laGetUiGap(laProp *sub, void* parent, void *Instance);
 void laGetCategory(laProp *sub, void* parent, void *Instance, char* buf, char** buf_ptr);
 int laCanGetState(laProp *sub);

+ 4 - 0
la_interface.h

@@ -2187,6 +2187,7 @@ void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actins
 void laui_DefaultSubWindowMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actinst, laColumn *extracol, int context);
 void laui_ThemeListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
 void laui_Theme(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
+void laui_ThemePreview(laUiList *uil, laPropPack *Base, laPropPack *This, laColumn *UNUSED_Colums, int context);
 void laui_BoxedThemeItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
 void laui_PropertyContainerList(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
 void laui_WindowListItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context);
@@ -2574,6 +2575,7 @@ void la_DestroyCanvasTemplate(laCanvasTemplate* uit);
 laUiTemplate *laRegisterUiTemplate(char *Identifier, char* Title, laUiDefineFunc func,laPanelDetachedPropFunc PropFunc, laUiDefineFunc header, char* NewCategory, int DefaultGLFormat, int DefaultW_RH, int DefaultH_RH);
 laCanvasTemplate *laRegisterCanvasTemplate(char *Identifier, char *ForContainer, laModalFunc ExtraModal, laCanvasDrawFunc Func, laUiDrawFunc SecondDraw, laUiInitFunc CustomInit, laUiDestroyFunc CustomDestroy);
 
+laTheme *laDuplicateTheme(laTheme* from);
 void la_DestroyTheme(laTheme* t);
 laTheme *laDesignTheme(const char *Name, const char *AuthorName);
 laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** BackRef,
@@ -2583,6 +2585,8 @@ laBoxedTheme *laGetBoxedTheme(const char *ThemeName, const char *BoxName);
 real* laThemeColor(laBoxedTheme* bt, int which);
 real* laAccentColor(int which);
 
+laTheme* la_CreateClassicLightTheme();
+laTheme* la_CreateClassicDarkTheme();
 void la_RefreshBoxedThemeColor(laBoxedTheme* bt);
 void la_RefreshThemeColorSelf(laTheme* th);
 void la_RefreshThemeColor(laTheme* th);

+ 77 - 27
la_kernel.c

@@ -1576,12 +1576,14 @@ void laSaveUserPreferences(){
     laWriteProp(udf,"la.user_preferences");
     laWriteProp(udf,"la.input_mapping");
     laWriteProp(udf,"la.controllers");
+    laWriteProp(udf,"la.themes");
     for(laListItemPointer* lip=MAIN.ExtraPreferencePaths.pFirst;lip;lip=lip->pNext){
         laWriteProp(udf,lip->p);
     }
     laPackUDF(udf,0,0);
 }
 void laEnsureUserPreferences(){
+    //laLoadHyperResources("LATHEME");
     char path[1024];
 #ifdef LAGUI_ANDROID
     sprintf(path,"%s/%s",MAIN.InternalDataPath,"preferences.udf");
@@ -2191,17 +2193,56 @@ void laSetInputProcessCallback(laInputProcessF InputProcess){
 
 //====================================================================================================
 
+laTheme *laDuplicateTheme(laTheme* from){
+    laTheme *t = memAcquireHyper(sizeof(laTheme));
+    strSafePrint(&t->Name, "~%s", SSTR(from->Name));
+    strSafeSet(&t->Author, SSTR(from->Author));
+    lstPushItem(&MAIN.Themes, t);
+    MAIN.CurrentTheme = t;
+    char buf[32]; sprintf(buf,"LATHEME_%.22s",SSTR(t->Name));
+    laset_InstanceUID(t, buf);
+
+    tnsVectorSet3v(t->Color,from->Color);
+    tnsVectorSet3v(t->AccentColor,from->AccentColor);
+    tnsVectorSet3v(t->WarningColor,from->WarningColor);
+    t->InactiveMix=from->InactiveMix;
+    t->InactiveSaturation=from->InactiveSaturation;
+    t->CursorAlpha=from->CursorAlpha;
+    t->SelectionAlpha=from->SelectionAlpha;
+    t->WireBrightness=from->WireBrightness;
+    t->WireSaturation=from->WireSaturation;
+    t->WireTransparency=from->WireTransparency;
+    t->EdgeBrightness=from->EdgeBrightness;
+    t->EdgeTransparency=from->EdgeTransparency;
+    t->VertexBrightness=from->VertexBrightness;
+    t->VertexTransparency=from->VertexTransparency;
+    t->SelectedFaceTransparency=from->SelectedFaceTransparency;
+    t->SelectedEdgeTransparency=from->SelectedEdgeTransparency;
+    t->SelectedVertexTransparency=from->SelectedVertexTransparency;
+    
+    for(laBoxedTheme* bt=from->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){
+        laBoxedTheme* new_bt = laDesignBoxedTheme(t,SSTR(bt->Name),bt->BackRef,
+            bt->NormalY,bt->ActiveY,bt->BorderY,bt->TextY,bt->TextActiveY,bt->Alpha);
+    }
+
+    la_RefreshThemeColor(t);
+    return t;
+}
 void la_DestroyTheme(laTheme* t){
+    MAIN.CurrentTheme = t->Item.pPrev?t->Item.pPrev:t->Item.pNext;
+    lstRemoveItem(&MAIN.Themes, t);
     laBoxedTheme*bt; while(bt=lstPopItem(&t->BoxedThemes)){ strSafeDestroy(&bt->Name); *bt->BackRef=0; memFree(bt); }
-    strSafeDestroy(&t->Name);
-    strSafeDestroy(&t->Author);
+    strSafeDestroy(&t->Name); strSafeDestroy(&t->Author);
+    memFree(t);
 }
 laTheme *laDesignTheme(const char *Name, const char *AuthorName){
     laTheme *t = memAcquireHyper(sizeof(laTheme));
     strSafeSet(&t->Name, Name);
     strSafeSet(&t->Author, AuthorName);
-    lstAppendItem(&MAIN.Themes, t);
+    lstPushItem(&MAIN.Themes, t);
     MAIN.CurrentTheme = t;
+    char buf[32]; sprintf(buf,"LATHEME_%.22s",Name);
+    laset_InstanceUID(t, buf);
     return t;
 }
 laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** BackRef,
@@ -2213,6 +2254,7 @@ laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** Ba
     bt->BorderY=BorderY;
     bt->TextY=TextY; bt->TextActiveY=TextActiveY; bt->Alpha = Alpha;
     bt->BackRef = BackRef;
+    memAssignRef(bt, &bt->Parent, t);
     lstAppendItem(&t->BoxedThemes, bt);
     return bt;
 }
@@ -2266,8 +2308,8 @@ real* laAccentColor(int which){
     return MAIN.CurrentTheme->SelectionColor;
 }
 void la_RefreshBoxedThemeColor(laBoxedTheme* bt){
-    real hcy[3];
-    tnsRGB2HCY(MAIN.CurrentTheme->Color,hcy);
+    real hcy[3]; if(!bt->Parent){ return; }
+    tnsRGB2HCY(bt->Parent->Color,hcy);
     hcy[2]=bt->NormalY; tnsHCY2RGB(hcy, bt->Normal); bt->Normal[3]=bt->Alpha;
     hcy[2]=bt->ActiveY; tnsHCY2RGB(hcy, bt->Active); bt->Active[3]=bt->Alpha;
     hcy[2]=bt->BorderY; tnsHCY2RGB(hcy, bt->Border); bt->Border[3]=1;
@@ -2275,6 +2317,7 @@ void la_RefreshBoxedThemeColor(laBoxedTheme* bt){
     hcy[2]=bt->TextActiveY; tnsHCY2RGB(hcy, bt->TextActive); bt->TextActive[3]=1;
 }
 void la_RefreshThemeColorSelf(laTheme* th){
+    if(!th) return;
     tnsVectorCopy3d(th->AccentColor, th->CursorColor);   th->CursorColor[3]=th->CursorAlpha;
     tnsVectorCopy3d(th->AccentColor, th->SelectionColor);th->SelectionColor[3]=th->SelectionAlpha; th->WarningColor[3]=th->SelectionAlpha;
     real hcy[3], usehcy[3];
@@ -2287,6 +2330,7 @@ void la_RefreshThemeColorSelf(laTheme* th){
     tnsVectorCopy3d(th->Color, th->ShadowColor); th->ShadowColor[3]=th->CursorAlpha;
 }
 void la_RefreshThemeColor(laTheme* th){
+    if(!th) return;
     real hcy[3], usehcy[3], normalhcy[3];
     tnsRGB2HCY(th->Color,hcy);
     la_RefreshThemeColorSelf(th);
@@ -2352,7 +2396,8 @@ int la_SetUpUiListMatrix(laUiListDraw *uild, laUiList *Target, int _L, int _R, i
     //   DifXY clamped distance
     //   
 
-    //if (Target__B - Target->U > LimH) Target__B = Target->U + LimH;
+    // why we still need this line
+    if (Target__B - Target->U > LimH) Target__B = Target->U + LimH;
     //if (Target__R - Target->L > LimW) Target__R = Target->L + LimW;
 
     uildi->XP = last ? last->XP + Target->PanX : Target->PanX;
@@ -2388,7 +2433,7 @@ int la_SetUpUiListMatrix(laUiListDraw *uild, laUiList *Target, int _L, int _R, i
         return 0;
     }
 
-    int Pad=1;
+    int Pad=2;
     tnsViewportWithScissor(uildi->L-Pad, PanelH - uildi->B-Pad, uildi->R - uildi->L+Pad*2, uildi->B - uildi->U+Pad*2);
     tnsOrtho(Target->L + Target->PanX + uildi->DifX-Pad,
              Target->L + Target->PanX + uildi->DifX+Pad+ (uildi->R - uildi->L),
@@ -4003,8 +4048,7 @@ laPanel *laEnablePropertyPanel(laPanel *Attachment, laOperator *a, laPropPack *O
 
     if (!def){
         if (This && This->LastPs->p){
-            if(This->LastPs->p->UiDefine) def = This->LastPs->p->UiDefine;
-            elif(This->LastPs->p->SubProp&&This->LastPs->p->SubProp->MenuUiDefine) def = This->LastPs->p->SubProp->MenuUiDefine;
+            if(This->LastPs->p->SubProp&&This->LastPs->p->SubProp->MenuUiDefine) def = This->LastPs->p->SubProp->MenuUiDefine;
         }
         if((!def) && (sub=la_EnsureSubTarget(This->LastPs->p,This->EndInstance)) && sub->MenuUiDefine) def=sub->MenuUiDefine;
         if(!def) def = FallBackUiDefine?FallBackUiDefine:laui_DefaultPropUiDefine;
@@ -6493,8 +6537,8 @@ void la_DrawUiListScrollerH(laUiList *uil, int DisplayOffset, int TotalW, int Di
 void la_DrawInstanceBkg(laUiList *uil, real* color, int LP, int RP){
     tnsUseNoTexture();
     tnsColor4dv(color);
-    tnsVertex2d(uil->L-LP, uil->U); tnsVertex2d(uil->R+RP, uil->U);
-    tnsVertex2d(uil->R+RP, uil->B); tnsVertex2d(uil->L-LP, uil->B);
+    tnsVertex2d(uil->L-LP+0.5, uil->U+0.5); tnsVertex2d(uil->R+RP-0.5, uil->U+0.5);
+    tnsVertex2d(uil->R+RP-0.5, uil->B-0.5); tnsVertex2d(uil->L-LP+0.5, uil->B-0.5);
     tnsPackAs(GL_TRIANGLE_FAN);
 }
 void la_InitSocketRecord(laUiListDraw* uild, laUiList* container){
@@ -6522,7 +6566,7 @@ void la_RecordSocket(laUiListDraw* uild, laUiList* uil, laUiItem* ui){
 }
 void la_RegenerateWireColors(){
     if(MAIN.WireColorCache) free(MAIN.WireColorCache);
-    laTheme* t=MAIN.CurrentTheme;
+    laTheme* t=MAIN.CurrentTheme; if(!t) return;
     MAIN.WireColorCache = calloc(1, sizeof(real)*4*MAIN.WireColorSlices);
     real hsl[]={0.0,0.8,0.6}; hsl[1]=t->WireSaturation; hsl[2]=t->WireBrightness;
     for(int i=0;i<MAIN.WireColorSlices;i++){
@@ -6742,6 +6786,12 @@ int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int
 
                     if ((!la_UiListInBoundEx(sub, uild)) && (!RegisterNodes)) continue;
 
+                    laTheme* SwitchedTheme=0;
+                    if(CanGetTheme){
+                        SwitchedTheme=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance);
+                        la_SwitchThemeQuick(SwitchedTheme, OriginalTheme);
+                    }
+
                     if(NeedDraw){ int drawn=0;
                         if (!(ui->Flags&LA_UI_COLLECTION_NO_HIGHLIGHT) && sub->Instance == Active){
                             la_DrawInstanceBkg(sub, laAccentColor(LA_BT_NORMAL),LA_M,LA_M); drawn=1;
@@ -6749,9 +6799,12 @@ int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int
                         if (CanGetState && !drawn){
                             State = laGetUiState(ui->PP.LastPs->p, sub->Instance);
                             if(State >= 0){
-                                la_DrawInstanceBkg(sub, laAccentColor(State),LA_M,LA_M);
+                                la_DrawInstanceBkg(sub, laAccentColor(State),LA_M,LA_M); drawn=1;
                             }
                         }
+                        if((!drawn) && SwitchedTheme){
+                            la_DrawInstanceBkg(sub, laThemeColor(_LA_THEME_FLOATING_PANEL ,LA_BT_NORMAL),LA_M,LA_M);
+                        }
                     }
 
                     if(sub->TabName && sub->TabName->Ptr){
@@ -6762,12 +6815,6 @@ int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int
                         tnsFlush();
                     }
 
-                    if(CanGetTheme){
-                        laTheme* t=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance);
-                        la_SwitchThemeQuick(t, OriginalTheme);
-                        if(t) la_DrawInstanceBkg(sub, laThemeColor(_LA_THEME_FLOATING_PANEL ,LA_BT_NORMAL),LA_M,LA_M);
-                    }
-
                     tnsFlush();
                     Ret += la_DrawUiListRecursive(uild, sub, L, R, U, B, 10000, ConditionStackLevel, RegisterNodes);
                     
@@ -6804,7 +6851,7 @@ int la_RejectByUiList(laOperator* a, int x, int y){
     laListItemPointer* lip=a->LocalUiLists.pFirst;
     if(lip){ laUiList* uil=lip->p;
         if(uil->FL!=uil->FR && (x < uil->FL || y < uil->FU || x > uil->FR || y > uil->FB)){
-            printf("rejected %d %d | %d %d %d %d\n",x,y,uil->FL,uil->FR,uil->FU,uil->FB);
+            //printf("rejected %d %d | %d %d %d %d\n",x,y,uil->FL,uil->FR,uil->FU,uil->FB);
             return 1;
         }
     }
@@ -7401,7 +7448,7 @@ void *la_DestroyOperator(laOperator **a, laListHandle *Operators, int OnlyThisOn
         MAIN.CurrentPanel = (*a)->OperatorPanel;
         laDestroySinglePanel((*a)->OperatorPanel,0);
     }
-    if ((*a)->CreatedThis) memFree((*a)->CreatedThis);
+    if ((*a)->CreatedThis){ la_FreePropStepCache((*a)->CreatedThis); memFree((*a)->CreatedThis); }
 
     if ((*a)->ExtraInstructionsP) strDestroyStringSplitor(&(*a)->ExtraInstructionsP);
 
@@ -7467,7 +7514,7 @@ void la_EnsureLocalizedEvent(laOperator *From, laOperator *a, laEvent *e){
         laWindowToLocal(0, a->ToPanel, &e->x, &e->y);
         e->Localized = 1;
     }
-    if (e&&e->Localized){
+    if (e&&e->Localized && From){
         if (!at->ExtraMark & LA_EXTRA_TO_PANEL){
             laLocalToWindow(From, From->ToPanel, &e->x, &e->y);
             e->Localized = 0;
@@ -7543,12 +7590,8 @@ int laInvokePCreateThis(laOperator *From, laOperatorType *at, laEvent *e, laProp
     if (!f && e&&e->Localized || !OrigionalThis || !OrigionalThis->LastPs) return -1;
 
     created = memAcquireSimple(sizeof(laPropPack));
-    created->LastPs = memAcquireSimple(sizeof(laPropStep));
-    created->Go = created->LastPs;
-    created->LastPs->p = OrigionalThis->LastPs->p;
-    created->LastPs->UseInstance = OrigionalThis->LastPs->UseInstance;
+    la_CopyPropPack(OrigionalThis, created);
     created->EndInstance = FromInstance;
-    created->LastIndex = OrigionalThis->LastIndex;
 
     a = la_CreateOperator(at);
     a->ToPanel = MAIN.ToPanel;
@@ -8355,6 +8398,13 @@ void la_DrawWindow(laWindow *w){
 void laset_UiRowHeight(void* unused, int val);
 int laFinalize(){
     if(!laValidateProperties()){ laShutoff(0); return 0; }
+
+    if(!MAIN.Themes.pFirst){
+        la_CreateClassicLightTheme();
+        la_CreateClassicDarkTheme();
+    }
+
+    la_RefreshThemeColor(MAIN.CurrentTheme);
     
     laUiTemplate* uit;
     while(uit=lstPopItem(&MAIN.InitPanelTemplates)) lstAppendItem(&MAIN.PanelTemplates,uit);

+ 30 - 31
la_resource.c

@@ -116,32 +116,8 @@ void la_RegisterWindowKeys(){
     laAssignNewKey(km, 0, "LA_system_paste", 0, LA_KEY_CTRL, LA_KEY_DOWN, 'v', 0);
 }
 
-void la_RegisterMainThemes(){
-    laBoxedTheme *bt;
-
-    strSafeSet(&MAIN.example_string,
-"hello(){\n"
-"    world!\n"
-"    This is a LaGUI application 🤔\n"
-"}");
-
-    la_UDFAppendSharedTypePointer("BT Panel", &_LA_THEME_PANEL);
-    la_UDFAppendSharedTypePointer("BT Floating Panel", &_LA_THEME_FLOATING_PANEL);
-    la_UDFAppendSharedTypePointer("BT Valuator", &_LA_THEME_VALUATOR);
-    la_UDFAppendSharedTypePointer("BT Button", &_LA_THEME_BUTTON);
-    la_UDFAppendSharedTypePointer("BT String", &_LA_THEME_STRING);
-    la_UDFAppendSharedTypePointer("BT Selector", &_LA_THEME_SELECTOR);
-    la_UDFAppendSharedTypePointer("BT Collection Selector", &_LA_THEME_COLLECTION_SELECTOR);
-    la_UDFAppendSharedTypePointer("BT Label", &_LA_THEME_LABEL);
-    la_UDFAppendSharedTypePointer("BT Tab", &_LA_THEME_TAB);
-    la_UDFAppendSharedTypePointer("BT Collection Group", &_LA_THEME_COLLECTION_GROUP);
-    la_UDFAppendSharedTypePointer("BT Collection Item", &_LA_THEME_COLLECTION_ITEM);
-    la_UDFAppendSharedTypePointer("BT 3D Viewer", &_LA_THEME_3D_VIEW);
-    la_UDFAppendSharedTypePointer("BT 2D Viewer", &_LA_THEME_2D_VIEW);
-    la_UDFAppendSharedTypePointer("BT Socket", &_LA_THEME_SOCKET);
-
-    laTheme *t;
-
+laTheme* la_CreateClassicLightTheme(){
+    laTheme *t; laBoxedTheme *bt;
     t = laDesignTheme("Classic Light", "YimingWu");{
         LA_SET3(t->Color, 0.58,0.58,0.55);
         LA_SET3(t->AccentColor, 0.27,0.47,0.79);
@@ -182,9 +158,11 @@ void la_RegisterMainThemes(){
 
         la_RefreshThemeColor(t);
     }
+    return t;
+}
 
-    laTheme* t1=t;
-
+laTheme* la_CreateClassicDarkTheme(){
+    laTheme *t; laBoxedTheme *bt;
     t = laDesignTheme("Classic Dark", "YimingWu");{
         LA_SET3(t->Color, 0.5,0.4,0.3);
         LA_SET3(t->AccentColor, 0.17,0.74,0.49);
@@ -196,13 +174,10 @@ void la_RegisterMainThemes(){
         t->SelectedFaceTransparency=0.6,t->SelectedEdgeTransparency=0.9, t->SelectedVertexTransparency=1.0;
         bt = laDesignBoxedTheme(t, "Panel",&_LA_THEME_PANEL,
             0.2, 0.2, 0.1, 0.7, 0.9, 0.8);
-            memAssignRef(bt, &bt->Parent, t1);
         bt = laDesignBoxedTheme(t, "Floating Panel",&_LA_THEME_FLOATING_PANEL,
             0.05, 0.05, 0.4, 0.8, 0.9, 0.8);
-            memAssignRef(bt, &bt->Parent, t1);
         bt = laDesignBoxedTheme(t, "Valuator",&_LA_THEME_VALUATOR,
             0.3, 0.1, 0.4, 0.8, 0.9, 0.9);
-            memAssignRef(bt, &bt->Parent, t1);
         bt = laDesignBoxedTheme(t, "Button",&_LA_THEME_BUTTON,
             0.1, 0.9, 0.3, 0.8, 0.1, 0.95);
         bt = laDesignBoxedTheme(t, "String",&_LA_THEME_STRING,
@@ -228,4 +203,28 @@ void la_RegisterMainThemes(){
 
         la_RefreshThemeColor(t);
     }
+    return t;
+}
+
+void la_RegisterMainThemes(){
+    strSafeSet(&MAIN.example_string,
+"hello(){\n"
+"    world!\n"
+"    This is a LaGUI application 🤔\n"
+"}");
+
+    la_UDFAppendSharedTypePointer("BT Panel", &_LA_THEME_PANEL);
+    la_UDFAppendSharedTypePointer("BT Floating Panel", &_LA_THEME_FLOATING_PANEL);
+    la_UDFAppendSharedTypePointer("BT Valuator", &_LA_THEME_VALUATOR);
+    la_UDFAppendSharedTypePointer("BT Button", &_LA_THEME_BUTTON);
+    la_UDFAppendSharedTypePointer("BT String", &_LA_THEME_STRING);
+    la_UDFAppendSharedTypePointer("BT Selector", &_LA_THEME_SELECTOR);
+    la_UDFAppendSharedTypePointer("BT Collection Selector", &_LA_THEME_COLLECTION_SELECTOR);
+    la_UDFAppendSharedTypePointer("BT Label", &_LA_THEME_LABEL);
+    la_UDFAppendSharedTypePointer("BT Tab", &_LA_THEME_TAB);
+    la_UDFAppendSharedTypePointer("BT Collection Group", &_LA_THEME_COLLECTION_GROUP);
+    la_UDFAppendSharedTypePointer("BT Collection Item", &_LA_THEME_COLLECTION_ITEM);
+    la_UDFAppendSharedTypePointer("BT 3D Viewer", &_LA_THEME_3D_VIEW);
+    la_UDFAppendSharedTypePointer("BT 2D Viewer", &_LA_THEME_2D_VIEW);
+    la_UDFAppendSharedTypePointer("BT Socket", &_LA_THEME_SOCKET);
 }

+ 39 - 16
resources/la_operators.c

@@ -986,6 +986,10 @@ int OPINV_UDFPropagate(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 
+int OPINV_Nop(laOperator *a, laEvent *e){
+    return LA_FINISHED;
+}
+
 int OPINV_SendSignal(laOperator *a, laEvent *e){
     const char* sig=strGetArgumentString(a->ExtraInstructionsP,"signal"); if((!sig) || (!sig[0])) return LA_FINISHED;
     laCustomSignal* cs=laFindSignal(sig);
@@ -999,7 +1003,7 @@ int OPINV_NewToolbox(laOperator *a, laEvent *e){
 int OPINV_RemoveToolbox(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMapping* im=a->This->EndInstance;
     char* buf[256];sprintf(buf,"%s \"%s\".",transLate("Will remove toolbox"),SSTR(im->Name));
-    laEnableYesNoPanel(0, 0, "Confirm?", buf, e->x, e->y, 200, e);
+    laEnableYesNoPanel(a, 0, "Confirm?", buf, e->x, e->y, 200, e);
     return LA_RUNNING;
 }
 int OPMOD_RemoveToolbox(laOperator *a, laEvent *e){
@@ -1028,7 +1032,7 @@ int OPINV_NewInputMapping(laOperator *a, laEvent *e){
 int OPINV_RemoveInputMapping(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMapping* im=a->This->EndInstance;
     char* buf[256];sprintf(buf,"%s \"%s\".",transLate("Will remove input mapping"),SSTR(im->Name));
-    laEnableYesNoPanel(0, 0, "Confirm?", buf, e->x, e->y, 200, e);
+    laEnableYesNoPanel(a, 0, "Confirm?", buf, e->x, e->y, 200, e);
     return LA_RUNNING;
 }
 int OPINV_NewInputMappingEntry(laOperator *a, laEvent *e){
@@ -1042,7 +1046,7 @@ int OPINV_NewInputMappingEntry(laOperator *a, laEvent *e){
 }
 int OPINV_RemoveInputMappingEntry(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_CANCELED; laInputMappingEntry* ie=a->This->EndInstance;
-    laEnableYesNoPanel(0, 0, "Confirm?", "Will remove this key map entry", e->x, e->y, 200, e);
+    laEnableYesNoPanel(a, 0, "Confirm?", "Will remove this key map entry", e->x, e->y, 200, e);
     return LA_RUNNING;
 }
 int OPINV_ClearInputMappingFields(laOperator *a, laEvent *e){
@@ -1235,7 +1239,7 @@ int OPMOD_RestoreFactorySettings(laOperator* a, laEvent* e){
     return LA_RUNNING;
 }
 int OPINV_RestoreFactorySettings(laOperator* a, laEvent* e){
-    laEnableYesNoPanel(0, 0, "Confirm?", "This will remove the preference file.\nChanges take effect on restating the program.", e->x, e->y, 200, e);
+    laEnableYesNoPanel(a, 0, "Confirm?", "This will remove the preference file.\nChanges take effect on restating the program.", e->x, e->y, 200, e);
     return LA_RUNNING;
 }
 
@@ -1968,16 +1972,33 @@ int OPINV_SwitchLayout(laOperator *a, laEvent *e){
 }
 
 int OPINV_DeleteTheme(laOperator *a, laEvent *e){
-    laTheme* t = a->This?a->This->EndInstance:MAIN.CurrentTheme;
-    if(!t || MAIN.Themes.pFirst == MAIN.Themes.pLast) return LA_CANCELED;
-
-    laBoxedTheme* NextBt;
-    for(laBoxedTheme* bt=t->BoxedThemes.pFirst; bt; bt=NextBt){
-        NextBt = bt->Item.pNext; lstRemoveItem(&t->BoxedThemes, bt); memFree(bt);
+    laTheme* th=a->This?a->This->EndInstance:MAIN.CurrentTheme;
+    char* buf[256];sprintf(buf,"%s \"%s\".",transLate("Will delete theme"),SSTR(th->Name));
+    laEnableYesNoPanel(a, 0, "Confirm?", buf, e->x-LA_RH*5, e->y-LA_RH*2, 200, e);
+    return LA_RUNNING;
+}
+int OPMOD_DeleteTheme(laOperator *a, laEvent *e){
+    laTheme* th=a->This?a->This->EndInstance:MAIN.CurrentTheme;
+    if(a->ConfirmData){
+        if(a->ConfirmData->Mode == LA_CONFIRM_OK){
+            laTheme* th=a->This?a->This->EndInstance:MAIN.CurrentTheme;
+            if(!th || MAIN.Themes.pFirst == MAIN.Themes.pLast) return LA_CANCELED;
+            la_DestroyTheme(th); la_RefreshThemeColor(MAIN.CurrentTheme);
+            laNotifyUsers("la.themes"); laRedrawAllWindows();
+        }
+        return LA_FINISHED;
     }
-    lstRemoveItem(&MAIN.Themes, t); memFree(t);
-    if(t==MAIN.CurrentTheme){MAIN.CurrentTheme = MAIN.Themes.pFirst;la_RefreshThemeColor(MAIN.CurrentTheme);}
-    laNotifyUsers("themes"); laRedrawCurrentWindow();
+    return LA_RUNNING;
+}
+int OPINV_NewTheme(laOperator *a, laEvent *e){
+    if(strArgumentMatch(a->ExtraInstructionsP,"duplicate","true")){
+        laTheme* th=a->This?a->This->EndInstance:MAIN.CurrentTheme; if(!th) return LA_CANCELED;
+        laTheme* newth=laDuplicateTheme(th);
+        laNotifyUsers("la.themes");
+        return LA_FINISHED;
+    }
+    la_CreateClassicDarkTheme();
+    laNotifyUsers("la.themes");
     return LA_FINISHED;
 }
 
@@ -2557,7 +2578,7 @@ int OPINV_RefreshScreens(laOperator *a, laEvent *e){
 }
 int OPINV_RemoveScreenConfig(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_FINISHED;
-    laEnableYesNoPanel(0, 0, "Confirm?", "Will remove this screen entry", e->x, e->y, 200, e);
+    laEnableYesNoPanel(a, 0, "Confirm?", "Will remove this screen entry", e->x, e->y, 200, e);
     return LA_RUNNING;
 }
 
@@ -2591,6 +2612,8 @@ void la_RegisterBuiltinOperators(){
     laCreateOperatorType("LA_terminate_program", "Quit", "Terminate Program Immediately",
                           OPCHK_TerminateProgram, 0, 0, OPINV_TerminateProgram, 0, U'⏻', LA_ACTUATOR_SYSTEM);
 
+    laCreateOperatorType("LA_nop", "Button", "Do nothing", 0, 0, 0, OPINV_Nop, 0, 0, LA_ACTUATOR_SYSTEM);
+
     laCreateOperatorType("LA_undo", "Undo", "Undo from recorded data state", OPCHK_Undo, 0, 0, OPINV_Undo, 0, U'⮌', LA_ACTUATOR_SYSTEM);
     laCreateOperatorType("LA_redo", "Redo", "Redo using recorded data state", OPCHK_Redo, 0, 0, OPINV_Redo, 0, U'⮎', LA_ACTUATOR_SYSTEM);
 
@@ -2801,6 +2824,6 @@ void la_RegisterBuiltinOperators(){
         ->ExtraInstructions = "feedback=CANCEL;";
     laCreateOperatorType("LA_pure_yes_no", "Yes Or No", "Show Yes Or No Box", 0, 0, 0, OPINV_PureYesNo, 0, U'❓', LA_ACTUATOR_SYSTEM);
     
-    laCreateOperatorType("LA_delete_theme", "Delete Theme", "Delete a theme",
-                               0, 0, 0, OPINV_DeleteTheme, 0, U'🞫', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_delete_theme", "Delete Theme", "Delete a theme", 0, 0, 0, OPINV_DeleteTheme, OPMOD_DeleteTheme, U'🞫', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_new_theme", "New Theme", "Create a new theme", 0, 0, 0, OPINV_NewTheme, 0, U'🞧', LA_ACTUATOR_SYSTEM);
 }

+ 22 - 5
resources/la_properties.c

@@ -33,6 +33,15 @@ void laset_TerminalInput(void* unused, char* content){
     strcpy(MAIN.TerminalInput,content);
 }
 
+void lapost_Theme(laTheme *th){
+    for(laBoxedTheme* bt=th->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){
+        memAssignRef(bt, &bt->Parent,th);
+    }
+    la_RefreshThemeColor(th);
+}
+laTheme* laget_ThemePreviewTheme(void* unused, laTheme* theme){
+    return theme;
+}
 void *laget_ActiveTheme(void *unused){ return MAIN.CurrentTheme; }
 void laset_ActiveTheme(void* unused, laTheme* t){
     if(!t) MAIN.CurrentTheme = MAIN.Themes.pFirst;
@@ -41,7 +50,11 @@ void laset_ActiveTheme(void* unused, laTheme* t){
     la_RegenerateWireColors();
     laRedrawAllWindows();
 }
-void laset_ThemeName(laTheme *t, char *content){ strSafeSet(&t->Name, content); }
+void laset_ThemeName(laTheme *t, char *content){
+    strSafeSet(&t->Name, content);
+    char buf[32]; sprintf(buf,"LATHEME_%.22s",content);
+    laset_InstanceUID(t, buf);
+}
 void laset_ThemeAuthor(laTheme *t, char *content){ strSafeSet(&t->Author, content); }
 void laset_ThemeColor(laTheme* t, real* array){
     tnsVectorCopy4d(array,t->Color);
@@ -1547,8 +1560,8 @@ void la_RegisterInternalProps(){
                 laAddSubGroup(p, "parent", "Parent", "Parent Theme", "theme",0,0,0,offsetof(laBoxedTheme, Parent), 0,0,0,0,0,0,0,LA_UDF_REFER);
             }
 
-            p = laAddPropertyContainer("theme", "Theme Package", "A package with all types of theme for ui items", 0,laui_Theme, sizeof(laTheme), 0,0,2);{
-                laAddStringProperty(p, "name", "Name", "Theme name", 0,0,0,0,1, offsetof(laTheme, Name), 0,0,0,0,LA_AS_IDENTIFIER);
+            p = laAddPropertyContainer("theme", "Theme Package", "A package with all types of theme for ui items", 0,laui_Theme, sizeof(laTheme), lapost_Theme,0,2);{
+                laAddStringProperty(p, "name", "Name", "Theme name", 0,0,0,0,1, offsetof(laTheme, Name), 0,0,laset_ThemeName,0,LA_AS_IDENTIFIER);
                 laAddStringProperty(p, "author", "Author", "The author's name", 0,0,0,0,1, offsetof(laTheme, Author), 0,0,0,0,0);
                 laAddSubGroup(p, "boxed_themes", "Boxed Themes", "The Boxed Theme For Single UiItem Or Panel", "boxed_theme",0,0,0,-1, 0,0,0,0,0,0,offsetof(laTheme, BoxedThemes), 0);
                 laAddFloatProperty(p, "color", "Color", "Base color of the theme", LA_WIDGET_FLOAT_COLOR, "R,G,B,A", 0,1, 0,0.025, 1, 0,offsetof(laTheme, Color), 0,0,4, 0,0,0,0,laset_ThemeColor, 0,0,0);
@@ -1568,8 +1581,12 @@ void la_RegisterInternalProps(){
                 laAddFloatProperty(p, "svertex_transparency", "Selected Vertex Transparency", "Transparency of selected vertices", 0,0,0,1, 0,0.05, 0.7, 0,offsetof(laTheme, SelectedVertexTransparency), 0,laset_ThemeSVertexTransparency, 0,0,0,0,0,0,0,0,0);
                 laAddFloatProperty(p, "sedge_transparency", "Selected Edge Transparency", "Transparency of selected edges", 0,0,0,1, 0,0.05, 0.7, 0,offsetof(laTheme, SelectedEdgeTransparency), 0,laset_ThemeSEdgeTransparency, 0,0,0,0,0,0,0,0,0);
                 laAddFloatProperty(p, "sface_transparency", "Selected Face Transparency", "Transparency of selected faces", 0,0,0,1, 0,0.05, 0.7, 0,offsetof(laTheme, SelectedFaceTransparency), 0,laset_ThemeSFaceTransparency, 0,0,0,0,0,0,0,0,0);
-
+                sp=laAddSubGroup(p,"preview","Preview","Theme preview","theme",0,0,0,-1,laget_Self,0,0,0,0,0,0,LA_READ_ONLY|LA_UDF_IGNORE|LA_UDF_REFER);
+                laSubGroupExtraFunctions(sp,0,0,laget_ThemePreviewTheme,0,0);
                 laAddOperatorProperty(p, "delete", "Delete", "Delete this theme", "LA_delete_theme", 0,0);
+                laAddOperatorProperty(p, "save_as", "Save As", "Save theme as file", "LA_udf_save_instance", U'🖫',0);
+                laAddOperatorProperty(p, "duplicate", "Duplicate", "Duplicate this theme", "LA_new_theme", U'⎘',0)
+                    ->ExtraInstructions="duplicate=true;";
             }
         }
 
@@ -1606,7 +1623,7 @@ void la_RegisterInternalProps(){
             laAddSubGroup(p, "user_preferences", "User Preference", "Kernel Settings For LA Main Structure", "la_user_preference",0,0,0,-1, laget_Main, 0,0,0,0,0,0,LA_UDF_LOCAL);
             laSubGroupExtraFunctions(sp,0,0,0,0,laget_PanelTemplateCategory);
 
-            laAddSubGroup(p, "themes", "Themes", "Themes Loded In The Program", "theme",0,0,laui_Theme, -1, 0,laget_ActiveTheme, 0,laset_ActiveTheme, 0,0,offsetof(LA,Themes), 0);
+            sp=laAddSubGroup(p, "themes", "Themes", "Themes Loded In The Program", "theme",0,0,laui_Theme, -1, 0,laget_ActiveTheme, 0,laset_ActiveTheme, 0,0,offsetof(LA,Themes), 0);
 
             sp=laAddSubGroup(p, "controllers", "Controllers", "Detected game controllers","la_controller",laget_ControllerType,0,0,-1,0,0,0,0,0,0,offsetof(LA,Controllers),0);
             laSubGroupDetachable(sp, laget_DetachedControllerFirst, laget_ListNext);

+ 101 - 34
resources/la_templates.c

@@ -666,7 +666,7 @@ void laui_Theme(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColu
     laColumn *col, *cl, *cr, *cll, *clr;
     laUiItem *sui;
     laUiList *tuil;
-    laUiItem *ui;
+    laUiItem *ui,*b;
 
     //col = laFirstColumn(uil);
     //tuil = laMakeGroup(uil, col, "����ժҪ", 0, 0)->Page; {
@@ -682,40 +682,98 @@ void laui_Theme(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColu
     //	laShowLabel(tuil, crr, 0, "EXEC", 0, 0, 0);
     //}
 
-    col = laFirstColumn(uil); laSplitColumn(uil,col,0.5);
+    col = laFirstColumn(uil); laSplitColumn(uil,col,0.65);
     cl=laLeftColumn(col,0); cr=laRightColumn(col,0);
+    
+    laShowLabel(uil,col,"Theme Details",0,0)->Flags|=LA_TEXT_ALIGN_CENTER;
 
-    ui=laBeginRow(uil,col, 0,0);
-    laShowItem(uil,col,Base, "delete");
-    laShowItem(uil,col,Base, "name")->Expand=1;
+    laShowItem(uil,cl,Base, "name");
+
+    ui=laBeginRow(uil,cr, 0,0);
+    laShowItem(uil,cr,Base, "duplicate");
+    laShowSeparator(uil,cr)->Expand=1;
+    laShowItem(uil,cr,Base, "delete")->Flags|=LA_UI_FLAGS_ICON;
     laEndRow(uil, ui);
+    
+    laShowSeparator(uil,col);
 
-    laShowLabel(uil, col, "Basics:",0,0);
-    laShowLabel(uil, cl, "Base Color:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT; laShowItem(uil, cr, Base, "color");
-    laShowLabel(uil, cl, "Accent Color:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT; laShowItem(uil, cr, Base, "accent_color");
-    laShowLabel(uil, cl, "Warning Color:",0,0)->Flags|=LA_TEXT_ALIGN_RIGHT; laShowItem(uil, cr, Base, "warning_color");
-    laShowItem(uil, cr, Base, "cursor_alpha");
-    laShowItem(uil, cr, Base, "selection_alpha");
-    laShowItem(uil, cr, Base, "inactive_mix");
-    laShowItem(uil, cr, Base, "inactive_saturation");
-
-    laShowLabel(uil, col, "Nodes:",0,0);
-    laShowItem(uil, cr, Base, "wire_brightness");
-    laShowItem(uil, cr, Base, "wire_saturation");
-    laShowItem(uil, cr, Base, "wire_transparency");
-
-    laShowLabel(uil, col, "Meshes:",0,0);
-    laShowItem(uil, cl, Base, "edge_transparency");
-    laShowItem(uil, cl, Base, "edge_brightness");
-    laShowItem(uil, cr, Base, "vertex_transparency");
-    laShowItem(uil, cr, Base, "vertex_brightness");
-    laShowItem(uil, col, Base, "svertex_transparency");
-    laShowItem(uil, col, Base, "sedge_transparency");
-    laShowItem(uil, col, Base, "sface_transparency");    
+    ui=laBeginRow(uil,col, 0,0);
+    b=laOnConditionToggle(uil,col,0,0,0,0,0);{
+        laShowLabel(uil,col,"Basics",0,0);
+        laEndRow(uil, ui);
+        laShowItem(uil, cl, Base, "color"); laShowLabel(uil, cr, "Base Color",0,0);
+        laShowItem(uil, cl, Base, "accent_color"); laShowLabel(uil, cr, "Accent Color",0,0);
+        laShowItem(uil, cl, Base, "warning_color"); laShowLabel(uil, cr, "Warning Color",0,0);
+        laShowItem(uil, cl, Base, "cursor_alpha");
+        laShowItem(uil, cl, Base, "selection_alpha");
+        laShowItem(uil, cr, Base, "inactive_mix");
+        laShowItem(uil, cr, Base, "inactive_saturation");
+    }laElse(uil,b);{
+        laShowLabel(uil,col,"Basics",0,0); laEndRow(uil, ui);
+    }laEndCondition(uil,b); 
+
+    ui=laBeginRow(uil,col, 0,0);
+    b=laOnConditionToggle(uil,col,0,0,0,0,0);{
+        laShowLabel(uil, col, "Nodes",0,0);
+        laEndRow(uil, ui);
+        laShowItem(uil, cl, Base, "wire_brightness");
+        laShowItem(uil, cl, Base, "wire_saturation");
+        laShowItem(uil, cl, Base, "wire_transparency");
+    }laElse(uil,b);{
+        laShowLabel(uil,col,"Nodes",0,0); laEndRow(uil, ui);
+    }laEndCondition(uil,b);
+
+    if(MAIN.InitArgs.HasWorldObjects){
+        ui=laBeginRow(uil,col, 0,0);
+        b=laOnConditionToggle(uil,col,0,0,0,0,0);{
+            laShowLabel(uil, col, "Meshes",0,0);
+            laEndRow(uil, ui);
+            laShowItem(uil, cl, Base, "edge_transparency");
+            laShowItem(uil, cl, Base, "edge_brightness");
+            laShowItem(uil, cr, Base, "vertex_transparency");
+            laShowItem(uil, cr, Base, "vertex_brightness");
+            laShowItem(uil, col, Base, "svertex_transparency");
+            laShowItem(uil, col, Base, "sedge_transparency");
+            laShowItem(uil, col, Base, "sface_transparency");   
+        }laElse(uil,b);{
+            laShowLabel(uil,col,"Meshes",0,0); laEndRow(uil, ui);
+        }laEndCondition(uil,b);  
+    }
+
+    laShowSeparator(uil,col);
 
     laShowLabel(uil, col, "Widgets:",0,0);
     laShowItem(uil, col, Base, "boxed_themes")->Flags|=(LA_UI_FLAGS_NO_DECAL|LA_UI_FLAGS_NO_GAP);
 }
+void laui_ThemePreviewFrame(laUiList *uil, laPropPack *Base, laPropPack *UnusedThis, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil); laUiItem* b,*ui;
+    laUiItem* gui=laMakeEmptyGroup(uil,c,"Boxed Theme",0); laUiList* gu=gui->Page; laColumn* gc=laFirstColumn(gu);
+    gui->Flags|=LA_UI_FLAGS_NO_DECAL;
+    laSplitColumn(gu,gc,0.4); laColumn* gcl=laLeftColumn(gc,0),*gcr=laRightColumn(gc,0);
+    b=laBeginRow(gu,gc,0,0);
+    laShowItemFull(gu,gc,0,"LA_nop",0,"text=⯆;",0,0)->Flags|=LA_UI_FLAGS_NO_EVENT;
+    laShowLabel(gu,gc,"Dialog",0,0)->Expand=1;
+    laShowItemFull(gu,gc,0,"LA_nop",0,"text=Close;icon=🞫;",0,0)->Flags|=LA_UI_FLAGS_NO_EVENT;
+    laEndRow(gu,b);
+    laShowSeparator(gu,gc);
+    laShowLabel(gu,gcl,"Text",0,0);
+    laShowLabel(gu,gcl,"Value",0,0);
+    laShowItem(gu,gcr,0,"la.example_string")->Flags|=LA_TEXT_ONE_LINE|LA_UI_FLAGS_NO_EVENT;
+    laShowItem(gu,gcr,0,"la.example_int")->Flags|=LA_UI_FLAGS_NO_EVENT;
+    b=laBeginRow(gu,gc,0,0);
+    laShowItemFull(gu,gc,0,"LA_nop",0,"text=Cancel;",0,0)->Flags|=LA_UI_FLAGS_NO_EVENT|LA_UI_FLAGS_WARNING;
+    laShowSeparator(gu,gc)->Expand=1;
+    laShowItem(gu,gc,0,"LA_nop")->Flags|=LA_UI_FLAGS_NO_EVENT;
+    laShowItemFull(gu,gc,0,"LA_nop",0,"text=Confirm;",0,0)->Flags|=LA_UI_FLAGS_NO_EVENT|LA_UI_FLAGS_HIGHLIGHT;
+    laEndRow(gu,b);
+}
+void laui_ThemePreview(laUiList *uil, laPropPack *Base, laPropPack *UnusedThis, laColumn *UNUSED_Colums, int context){
+    laColumn* c=laFirstColumn(uil); laUiItem* b,*ui;
+    ui=laShowItem(uil,c,Base,"name"); ui->Expand=1;
+    ui->Flags|=LA_UI_FLAGS_PLAIN|LA_TEXT_ALIGN_CENTER|LA_UI_FLAGS_NO_EVENT;
+    ui=laShowItemFull(uil,c,Base,"preview",0,0,laui_ThemePreviewFrame,0);
+    ui->Flags|=LA_UI_FLAGS_NO_EVENT;
+}
 void laui_BoxedThemeItem(laUiList *uil, laPropPack *Base, laPropPack *UNUSED_This, laColumn *UNUSED_Colums, int context){
     laColumn *col, *cl, *cr, *crl,*crr;
     laUiItem *bracket;
@@ -1443,15 +1501,24 @@ void laui_UserPreference(laUiList *uil, laPropPack *Base, laPropPack *OperatorIn
 
         muil = laAddTabPage(bracket, "Theme");{
             //muil->HeightCoeff = -1;
-            mc = laFirstColumn(muil); laSplitColumn(muil,mc,0.4);
-            mcl=laLeftColumn(mc,7);mcr=laRightColumn(mc,0);
+            mc = laFirstColumn(muil);
+            //laSplitColumn(muil,mc,0.4); mcl=laLeftColumn(mc,7);mcr=laRightColumn(mc,0);
 
-            if(MAIN.PreferencePageTheme){ MAIN.PreferencePageTheme(muil,0,0,0,0); }
+            if(MAIN.PreferencePageTheme){ MAIN.PreferencePageTheme(muil,0,0,0,0); laShowSeparator(muil,mc); }
 
-            laShowLabel(muil, mcl, "Active Theme", 0, 0);
-            laShowItemFull(muil, mcr, 0, "la.themes", LA_WIDGET_COLLECTION_SELECTOR, 0,laui_ThemeListItem,0);
-            laShowSeparator(muil,mc);
-            laShowItemFull(muil, mc, 0, "la.themes", LA_WIDGET_COLLECTION_SINGLE, 0 ,0,0)->Flags|=LA_UI_FLAGS_NO_DECAL;
+            laUiItem* gui=laMakeGroup(muil,mc,"Installed Themes",0); laUiList* gu=gui->Page; laColumn* gc=laFirstColumn(gu);
+            gu->HeightCoeff=10;
+            laUiItem* ui=laShowItemFull(gu, gc, 0, "la.themes", 0, 0,laui_ThemePreview,0);
+            ui->Expand=10; ui->Flags|=LA_UI_FLAGS_NO_DECAL;
+
+            laUiItem* b=laBeginRow(muil,mc,0,0);
+            laShowSeparator(muil,mc)->Expand=1;
+            laShowItem(muil,mc,0,"LA_new_theme");
+            laEndRow(muil,b);
+
+            //laShowItemFull(muil, mc, 0, "la.themes", LA_WIDGET_COLLECTION_SELECTOR, 0,laui_ThemeListItem,0);
+            //laShowSeparator(muil,mc);
+            laShowItemFull(muil, mc, 0, "la.themes", LA_WIDGET_COLLECTION_SINGLE, 0 ,0,0);//->Flags|=LA_UI_FLAGS_NO_DECAL;
         }
 
         muil = laAddTabPage(bracket, "System");{

+ 6 - 6
resources/la_translations_es-ES.c

@@ -190,7 +190,7 @@ static const char *entries[]={
 "Keyboard","Teclado",
 "New Entry","Nueva Entrada",
 "New Mapping","Nuevo Mapeo",
-"Warning Color:","Color de Advertencia:",
+"Warning Color","Color de Advertencia",
 "Viewport:","Viewport:",
 "Halftone Factor","Factor de Semitono",
 "Halftone Size","Tamaño de Semitono",
@@ -394,7 +394,7 @@ static const char *entries[]={
 "Scrolling Speed","Velocidad de Desplazamiento",
 "Redo","Rehacer",
 "A graphical user interface application toolkit","Un conjunto de herramientas para aplicaciones de Interfaz Gráfica de Usuario",
-"Meshes:","Mallas:",
+"Meshes","Mallas",
 "Add Resource Folder","Agregar Carpeta de Recursos",
 "User Interactions:","Interacciones de Usuario:",
 "Enable Translation:","Activar Traducción:",
@@ -418,7 +418,7 @@ static const char *entries[]={
 "New Panel","Nuevo Panel",
 "Font Size:","Tamaño de fuente:",
 "Border","Límite",
-"Accent Color:","Color de Acentuado:",
+"Accent Color","Color de Acentuado",
 "Wire Saturation","Saturación de los cables",
 "Text","Texto",
 "LaGUI application framework is made by Wu Yiming.","Marco de Aplicación LaGUI programado por Wu Yiming.",
@@ -434,7 +434,7 @@ static const char *entries[]={
 "Hide","Ocultar",
 "Viewing Texture:","Textura de Visualización:",
 "Stylus Device","Dispositivo de Pluma",
-"Base Color:","Color de Base:",
+"Base Color","Color de Base",
 "Margin Size:","Tamaño de Márgen:",
 "Eraser Device","Dispositivo Borrador",
 "Animation Speed","Velocidad de Animación",
@@ -472,7 +472,7 @@ static const char *entries[]={
 "Get Folder Path","Obtener Ruta de Carpeta",
 "New SYSWINDOW","Nueva Ventana",
 "Resource Folders","Carpetas de Recursos",
-"Basics:","Basicos:",
+"Basics","Basicos",
 "Selected Edge Transparency","Transparencia de Borde Seleccionado",
 "Read","Abrir",
 "Wire thickness","Grosor de los cables",
@@ -484,7 +484,7 @@ static const char *entries[]={
 "Move Rack","Mover Rack",
 "Yes","Si",
 "Interface Size","Tamaño de Interfaz",
-"Nodes:","Nodos:",
+"Nodes","Nodos",
 "Translation:","Traducción:",
 "Delete","Eliminar",
 "(C)Yiming Wu","(C) Yiming Wu",

+ 6 - 6
resources/la_translations_zh-hans.c

@@ -185,7 +185,7 @@ static const char *entries[]={
 "Keyboard","键盘",
 "New Entry","新条目",
 "New Mapping","新建映射",
-"Warning Color:","警告颜色",
+"Warning Color","警告颜色",
 "Viewport:","视口:",
 "Halftone Factor","半调色程度",
 "Halftone Size","半调色尺寸",
@@ -389,7 +389,7 @@ static const char *entries[]={
 "Scrolling Speed","滚动速度",
 "Redo","重做",
 "A graphical user interface application toolkit","一个图形界面应用程序框架",
-"Meshes:","网格",
+"Meshes","网格",
 "Add Resource Folder","添加资源文件夹",
 "User Interactions:","用户交互:",
 "Enable Translation:","使用翻译:",
@@ -413,7 +413,7 @@ static const char *entries[]={
 "New Panel","新面板",
 "Font Size:","字符尺寸:",
 "Border","边框",
-"Accent Color:","亮点颜色",
+"Accent Color","亮点颜色",
 "Wire Saturation","线条饱和度",
 "Text","文字",
 "LaGUI application framework is made by Wu Yiming.","LaGUI应用程序框架由吴奕茗制作。",
@@ -429,7 +429,7 @@ static const char *entries[]={
 "Hide","隐藏",
 "Viewing Texture:","查看贴图:",
 "Stylus Device","手写笔设备",
-"Base Color:","基础颜色",
+"Base Color","基础颜色",
 "Margin Size:","留白尺寸:",
 "Eraser Device","橡皮擦设备",
 "Animation Speed","动画速度",
@@ -467,7 +467,7 @@ static const char *entries[]={
 "Get Folder Path","获得文件夹路径",
 "New SYSWINDOW","新窗口",
 "Resource Folders","资源文件夹",
-"Basics:","基础",
+"Basics","基础",
 "Selected Edge Transparency","已选择边的透明度",
 "Read","读取",
 "Wire thickness","线条粗细",
@@ -479,7 +479,7 @@ static const char *entries[]={
 "Move Rack","移动挂架",
 "Yes","是",
 "Interface Size","界面尺寸",
-"Nodes:","节点",
+"Nodes","节点",
 "Translation:","翻译:",
 "Delete","删除",
 "(C)Yiming Wu","(C) 吴奕茗",

+ 4 - 1
resources/la_widgets.c

@@ -2845,8 +2845,9 @@ int OPMOD_Button(laOperator *a, laEvent *e){
     laBoxedTheme *bt = (*ui->Type->Theme);
     int lx, ly;
     int Away = 0;
+    int NoEvent = ui->Flags&LA_UI_FLAGS_NO_EVENT;
 
-    if (e->type == LA_TIME_IDLE && !ui->State){
+    if (e->type == LA_TIME_IDLE && (!ui->State) && (!NoEvent)){
         int GX = e->x, GY = e->y; laLocalToWindow(a, a->ToPanel, &GX, &GY);
         laPanel *p = laEnableIdlePanel(a->ToPanel, a,  &ui->ExtraPP, 0,  &ui->PP, GX, GX + 150, GY, 600, 200, e);
         return LA_RUNNING;
@@ -2862,6 +2863,8 @@ int OPMOD_Button(laOperator *a, laEvent *e){
         return LA_FINISHED_PASS;
     }
 
+    if(NoEvent){ return LA_RUNNING_PASS; }
+
     if (e->type == LA_L_MOUSE_DOWN){
         ui->State = LA_UI_ACTIVE;
         laRedrawCurrentPanel();