*/}}
Explorar el Código

Preliminary proofing UI

YimingWu hace 3 días
padre
commit
f18607015d

+ 2 - 0
CMakeLists.txt

@@ -22,6 +22,7 @@ if(NOT (${LAGUI_ANDROID}))
     find_package(X11 REQUIRED)
     find_package(Freetype REQUIRED)
     find_package(GLEW REQUIRED)
+    find_package(LCMS2 REQUIRED)
     find_package(LuaJIT)
     find_package(PNG)
 endif()
@@ -158,4 +159,5 @@ install(TARGETS lagui EXPORT lagui-targets DESTINATION lib/lagui)
 install(EXPORT lagui-targets DESTINATION lib/lagui)
 install(FILES lagui-config.cmake DESTINATION lib/lagui)
 install(FILES FindLuaJIT.cmake DESTINATION lib/lagui)
+install(FILES FindLCMS2.cmake DESTINATION lib/lagui)
 install(FILES ${LAGUI_FONTS} DESTINATION ${LAGUI_FONT_CUSTOM_PATH})

+ 17 - 0
FindLCMS2.cmake

@@ -0,0 +1,17 @@
+find_path(LCMS2_INCLUDE_DIR lcms2.h PATHS /usr/include /usr/local/include /opt/include /opt/local/include)
+
+set(LCMS2_NAMES ${LCMS2_NAMES} lcms2 liblcms2 liblcms2_static)
+
+find_library(LCMS2_LIBRARY NAMES ${LCMS2_NAMES} )
+
+mark_as_advanced(LCMS2_INCLUDE_DIR LCMS2_LIBRARY)
+
+# handle the QUIETLY and REQUIRED arguments and set LCMS2_FOUND to TRUE if
+# all listed variables are TRUE
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LCMS2  DEFAULT_MSG  LCMS2_LIBRARY  LCMS2_INCLUDE_DIR)
+
+if(LCMS2_FOUND)
+  set( LCMS2_INCLUDE_DIRS ${LCMS2_INCLUDE_DIR})
+  set( LCMS2_LIBRARIES ${LCMS2_LIBRARY} )
+endif()

+ 0 - 3
la_data.c

@@ -2039,9 +2039,6 @@ void laSetActiveInstance(laProp *sub, void *FromInstance, void *Instance){
             laNotifySubPropUsers(sp, FromInstance);
             sp->Set(FromInstance, Instance);
         }
-        if(sub->OffsetIsPointer && sub->Offset==0){
-            printf("where did that come from\n");
-        }
         if (sub->OffsetIsPointer && sub->Offset>=0){
             void **a = (void **)((BYTE *)FromInstance + sub->Offset);
             laNotifySubPropUsers(sp, FromInstance);

+ 10 - 0
la_interface.h

@@ -336,6 +336,14 @@ STRUCTURE(laProgressDisplay){
     int Called,Shown;
 };
 
+STRUCTURE(laProofingLUT){
+    laListItem Item;
+    laSafeString* Name;
+    uint8_t* TablesRGB; // 33 points
+    uint8_t* TableClay; // 33 points
+    uint8_t* TableD65P3; // 33 points
+};
+
 STRUCTURE(laInitArguments){
     int GLMajor,GLMinor,BufferSamples;
     int GLESMajor,GLESMinor;
@@ -356,6 +364,7 @@ NEED_STRUCTURE(laInputMappingBundle);
 
 #define LA_LUT_PRECISION 33
 #define LA_LUT_PIXCOUNT (LA_LUT_PRECISION * LA_LUT_PRECISION * LA_LUT_PRECISION)
+#define LA_LUT_VAL (LA_LUT_PRECISION-1)
 
 STRUCTURE(LA){
     laListItem Hyper;
@@ -384,6 +393,7 @@ STRUCTURE(LA){
     laListHandle Windows;
     laListHandle WastedPanels;
     laListHandle Screens;
+    laListHandle ProofingLUTs;
     int AutoSwitchColorSpace;
 
     laConfirmData *InvokeConfirmData;

+ 8 - 3
la_kernel.c

@@ -1024,6 +1024,10 @@ void la_InitProgressWindow(){
 #endif
 }
 
+void la_InitProofingLut(){
+
+}
+
 void laSetFontFolderPath(char* absolute){
     strcpy(MAIN.SysFontDir,absolute); int len=strlen(MAIN.SysFontDir);
     if(MAIN.SysFontDir[len-1]!='/'){ MAIN.SysFontDir[len]='/'; MAIN.SysFontDir[len+1]=0; }
@@ -1451,9 +1455,9 @@ int laGetReadyWith(laInitArguments* ia){
 
     if(MAIN.InitArgs.EnableLogStdOut){ MAIN.EnableLogStdOut=1; }
 
-    laSetProofingLut(DATA_LUT_PROOF_SRGB, 0);
-    laSetProofingLut(DATA_LUT_PROOF_CLAY, 1);
-    laSetProofingLut(DATA_LUT_PROOF_D65P3, 2);
+    //laSetProofingLut(DATA_LUT_PROOF_SRGB, 0);
+    //laSetProofingLut(DATA_LUT_PROOF_CLAY, 1);
+    //laSetProofingLut(DATA_LUT_PROOF_D65P3, 2);
 
     logPrintNew("Initialization Completed\n");
     MAIN.InitDone=1;
@@ -2387,6 +2391,7 @@ void la_RefreshProofingLut(){
     tnsEnableShaderv(T->immShader);
     tnsShader* s = T->immShader;
     if(!MAIN.ProofingLUT[table] || !MAIN.CurrentWindow->OutputProofing){
+        if(!MAIN.ProofingLUT[table]){ MAIN.CurrentWindow->OutputProofing=0; }
         return;
     }
 

+ 5 - 0
lagui-config.cmake

@@ -22,6 +22,7 @@ find_package(OpenGL REQUIRED)
 find_package(X11 REQUIRED)
 find_package(Freetype REQUIRED)
 find_package(GLEW REQUIRED)
+find_package(LCMS2 REQUIRED)
 find_package(PNG)
 find_package(LuaJIT)
 
@@ -47,6 +48,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
         ${GLEW_LIBRARIES}
         ${LAGUI_GL_LIB}
         ${FREETYPE_LIBRARIES}
+        ${LCMS2_LIBRARIES}
         ${X11_Xfixes_LIB}
         ${X11_Xrandr_LIB}
         m X11 Xi Xcursor
@@ -62,6 +64,7 @@ if (CMAKE_SYSTEM_NAME MATCHES "Linux")
         ${X11_INCLUDE_DIR}
         ${GLEW_INCLUDE_PATH}
         ${FREETYPE_INCLUDE_DIRS}
+        ${LCMS2_INCLUDE_DIR}
         ${LAGUI_INCLUDE_DIRS}
         CACHE INTERNAL "Include dirs of LaGUI and dependencies"
     )
@@ -79,6 +82,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
         ${OPENGL_LIBRARY}
         ${FREETYPE_LIBRARIES}
         ${CMAKE_DL_LIBS}
+        ${LCMS2_LIBRARIES}
         Threads::Threads
         lagui shlwapi Shcore Imm32
         CACHE INTERNAL "LaGUI shared libs"
@@ -87,6 +91,7 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
         ${CMAKE_SOURCE_DIR}
         ${GLEW_INCLUDE_PATH}
         ${FREETYPE_INCLUDE_DIRS}
+        ${LCMS2_INCLUDE_DIR}
         ${LAGUI_INCLUDE_DIRS}
         CACHE INTERNAL "Include dirs of LaGUI and dependencies"
     )

+ 107 - 1
resources/la_operators.c

@@ -17,6 +17,7 @@
 */
 
 #include "../la_5.h"
+#include "lcms2.h"
 
 extern LA MAIN;
 extern struct _tnsMain *T;
@@ -2644,7 +2645,6 @@ int OPINV_RemoveScreenConfig(laOperator *a, laEvent *e){
     laEnableYesNoPanel(a, 0, "Confirm?", "Will remove this screen entry", e->x, e->y, 200, e);
     return LA_RUNNING;
 }
-
 int OPMOD_RemoveScreenConfig(laOperator *a, laEvent *e){
     if(!a->This || !a->This->EndInstance) return LA_FINISHED; laScreen* s=a->This->EndInstance;
     if(a->ConfirmData){
@@ -2656,6 +2656,109 @@ int OPMOD_RemoveScreenConfig(laOperator *a, laEvent *e){
     return LA_FINISHED;
 }
 
+static cmsHPROFILE la_CreateProfileClay(){
+    cmsToneCurve* Gamma[3]; cmsHPROFILE hProfile; cmsCIExyY D65;
+    cmsCIExyYTRIPLE Primaries = { {0.64, 0.33, 1 }, {0.21, 0.71, 1 }, {0.15, 0.06, 1 } };
+    Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildGamma(0, 2.19921875);
+    cmsWhitePointFromTemp(&D65, 6504);
+    hProfile = cmsCreateRGBProfile(&D65, &Primaries, Gamma);
+    cmsFreeToneCurve(Gamma[0]);
+    return hProfile;
+}
+static cmsHPROFILE la_CreateProfileD65P3(){
+    cmsToneCurve* Gamma[3]; cmsHPROFILE hProfile; cmsCIExyY D65;
+    cmsCIExyYTRIPLE Primaries = { {0.680,0.320,1.0}, {0.265,0.690,1.0}, {0.150,0.060,1.0} };
+    cmsFloat64Number srgb_parameters[5] = { 2.4, 1.0 / 1.055,  0.055 / 1.055, 1.0 / 12.92, 0.04045 };
+    Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildParametricToneCurve(NULL, 4, srgb_parameters);
+    cmsWhitePointFromTemp(&D65, 6504);
+    hProfile = cmsCreateRGBProfile(&D65, &Primaries, Gamma);
+    cmsFreeToneCurve(Gamma[0]);
+    return hProfile;
+}
+static int la_InitProofLUT(void** lut, cmsHPROFILE cmyk_profile, cmsHPROFILE rgb_profile){
+    cmsHTRANSFORM htransform=cmsCreateProofingTransform(rgb_profile,TYPE_RGB_DBL,rgb_profile,TYPE_RGB_8,cmyk_profile,
+        INTENT_ABSOLUTE_COLORIMETRIC,INTENT_ABSOLUTE_COLORIMETRIC,cmsFLAGS_HIGHRESPRECALC|cmsFLAGS_SOFTPROOFING|cmsFLAGS_NOOPTIMIZE);
+    if(!htransform){ (*lut)=0; return 0; }
+    real data[LA_LUT_PIXCOUNT*3];
+    real cmyk8[LA_LUT_PIXCOUNT*4];
+    int prec=LA_LUT_PRECISION;
+    for(int i=0;i<prec;i++){
+        int counti=i*prec*prec;
+        for(int j=0;j<prec;j++){
+            int countj=j*prec;
+            for(int k=0;k<prec;k++){
+                real* p=&data[(counti+countj+k)*3];
+                p[0]=((real)i)/LA_LUT_VAL; p[1]=((real)j)/LA_LUT_VAL; p[2]=((real)k)/LA_LUT_VAL;
+            }
+        }
+    }
+
+    *lut=malloc(sizeof(char)*3*LA_LUT_PIXCOUNT);
+    char* table = *lut;
+    cmsDoTransform(htransform,data,table,LA_LUT_PIXCOUNT);
+}
+static int la_LoadProofingICC(char* path){
+    cmsHPROFILE cmyk = cmsOpenProfileFromFile(path,"r");
+    cmsHPROFILE srgb = cmsCreate_sRGBProfile();
+    cmsHPROFILE clay = la_CreateProfileClay();
+    cmsHPROFILE d65p3 = la_CreateProfileD65P3();
+    char* lut1,*lut2,*lut3;
+    la_InitProofLUT(&lut1,cmyk,srgb); if(!lut1){ return 0; }
+    la_InitProofLUT(&lut2,cmyk,srgb); if(!lut2){ free(lut1); return 0; }
+    la_InitProofLUT(&lut3,cmyk,srgb); if(!lut3){ free(lut1);free(lut2); return 0; }
+
+    laProofingLUT *pl=memAcquire(sizeof(laProofingLUT));
+    char* name=strGetLastSegment(path,LA_PATH_SEP);
+    strSafeSet(&pl->Name,name);
+    pl->TablesRGB=lut1; pl->TableClay=lut2; pl->TableD65P3=lut3;
+
+    laSetProofingLut(lut1,0); laSetProofingLut(lut2,1); laSetProofingLut(lut3,2);
+
+    lstAppendItem(&MAIN.ProofingLUTs,pl);
+    return 1;
+}
+static void la_RemoveProofingProfile(laProofingLUT* pl){
+    laProofingLUT* npl=pl->Item.pNext?pl->Item.pNext:pl->Item.pPrev;
+    free(pl->TablesRGB); free(pl->TableClay); free(pl->TableD65P3);
+    strSafeDestroy(&pl->Name); lstRemoveItem(&MAIN.ProofingLUTs,pl); memFree(pl);
+    if(npl){
+        laSetProofingLut(npl->TablesRGB,0); laSetProofingLut(npl->TableClay,1); laSetProofingLut(npl->TableD65P3,2);
+    }else{
+        laSetProofingLut(0,0); laSetProofingLut(0,1); laSetProofingLut(0,2);
+    }
+}
+int OPINV_NewProofingLUT(laOperator *a, laEvent *e){
+    laInvoke(a, "LA_file_dialog", e, 0, "filter_extensions=icc;use_extension=icc", 0);
+    return LA_RUNNING;
+}
+int OPMOD_NewProofingLUT(laOperator *a, laEvent *e){
+    if(a->ConfirmData){
+        if(a->ConfirmData->Mode==LA_CONFIRM_OK){
+            if(a->ConfirmData->StrData){
+                if(!la_LoadProofingICC(a->ConfirmData->StrData)){
+                    laEnableMessagePanel(a,0,"Error","Could not load this color profile to use for proofing.",e->x,e->y,LA_RH*15,e);
+                }
+            }
+        }
+        return LA_FINISHED;
+    }
+    return LA_RUNNING;
+}
+int OPINV_RemoveProofingLUT(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance) return LA_FINISHED;
+    laEnableYesNoPanel(a, 0, "Confirm?", "Will remove this profile", e->x, e->y, 200, e);
+    return LA_RUNNING;
+}
+int OPMOD_RemoveProofingLUT(laOperator *a, laEvent *e){
+    if(!a->This || !a->This->EndInstance) return LA_FINISHED; laProofingLUT* pl=a->This->EndInstance;
+    if(a->ConfirmData){
+        if(a->ConfirmData->Mode == LA_CONFIRM_OK){
+            la_RemoveProofingProfile(pl); laNotifyUsers("la.user_preferences.proofing_profiles");
+        }
+        return LA_FINISHED;
+    }
+    return LA_FINISHED;
+}
 
 int OPINV_OpenInternetLink(laOperator *a, laEvent *e){
     char *link = strGetArgumentString(a->ExtraInstructionsP, "link");
@@ -2894,4 +2997,7 @@ void la_RegisterBuiltinOperators(){
     
     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);
+
+    laCreateOperatorType("LA_new_proofing_profile", "New Proofing Profile", "Load an CMYK type icc color profile for soft proofing", 0, 0, 0, OPINV_NewProofingLUT, OPMOD_NewProofingLUT, U'🞧', LA_ACTUATOR_SYSTEM);
+    laCreateOperatorType("LA_remove_proofing_profile", "Remove Proofing Profile", "Remove this proofing profile", 0, 0, 0, OPINV_RemoveProofingLUT, OPMOD_RemoveProofingLUT, U'🞫', LA_ACTUATOR_SYSTEM);
 }

+ 49 - 0
resources/la_properties.c

@@ -1141,6 +1141,45 @@ int laaction_VerifyRootObject(void* Parent, laPropContainer* ParentType, void* C
     return 0;
 }
 
+
+void* lagetraw_ProofingData(laProofingLUT* pl, int* r_size, int* ret_is_copy){
+    int single_size=LA_LUT_PIXCOUNT*3;
+    *r_size=3*sizeof(char)*single_size; // 3x rgb x pixcount
+    *ret_is_copy=1;
+    void* data=malloc(*r_size);
+    memcpy(data,pl->TablesRGB,single_size);
+    memcpy(&data[single_size],pl->TableClay,single_size);
+    memcpy(&data[single_size*2],pl->TableD65P3,single_size);
+    return data;
+}
+void lasetraw_ProofingData(laProofingLUT* pl, void* data, int DataSize){
+    int single_size=LA_LUT_PIXCOUNT*3; if(DataSize<single_size*3) return;
+    if(!pl->TablesRGB)pl->TablesRGB=malloc(single_size);   memcpy(pl->TablesRGB,data,single_size);
+    if(!pl->TableClay)pl->TableClay=malloc(single_size);   memcpy(pl->TableClay,&data[single_size],single_size);
+    if(!pl->TableD65P3)pl->TableD65P3=malloc(single_size); memcpy(pl->TableD65P3,&data[single_size*2],single_size);
+}
+void laset_ActiveProofingProfile(void* unused, laProofingLUT* pl){
+    if(!pl->TablesRGB || !pl->TableD65P3 || !pl->TableClay){ return; }
+    laSetProofingLut(pl->TablesRGB,0); laSetProofingLut(pl->TableClay,1); laSetProofingLut(pl->TableD65P3,2);
+}
+int lagetstate_ProofingProfile(laProofingLUT* pl){
+    if(pl->TablesRGB==MAIN.ProofingLUT[0]) return 1; return -1;
+}
+void laset_ProofingProfileMove(laProofingLUT* pl, int move){
+    if(move<0 && pl->Item.pPrev){ lstMoveUp(&MAIN.ProofingLUTs, pl); laNotifyUsers("la.user_preferences.proofing_profiles"); }
+    elif(move>0 && pl->Item.pNext){ lstMoveDown(&MAIN.ProofingLUTs, pl); laNotifyUsers("la.user_preferences.proofing_profiles"); }
+}
+int laget_CurrentProofingID(void* unused){
+    int i=0; for(laProofingLUT* pl=MAIN.ProofingLUTs.pFirst;pl;pl=pl->Item.pNext){ if(pl->TablesRGB==MAIN.ProofingLUT[0]) break; i++; }
+    return i;
+}
+void laset_CurrentProofingID(void* unused, int id){
+    laProofingLUT* pl=MAIN.ProofingLUTs.pFirst; for(int i=0;i<id && pl;i++){ if(pl->TablesRGB==MAIN.ProofingLUT[0]) break; pl=pl->Item.pNext; }
+    if(!pl) return;
+    laSetProofingLut(pl->TablesRGB,0); laSetProofingLut(pl->TableClay,1); laSetProofingLut(pl->TableD65P3,2);
+}
+
+
 void lareset_Main(void* Unused){
     return;
 }
@@ -1835,6 +1874,9 @@ void la_RegisterInternalProps(){
             laAddEnumItemAs(ep, "NONE", "None", "Do not do color management on the window", 0, 0);
             laAddEnumItemAs(ep, "ENABLED", "Enabled", "Enable color management on the window", 1, 0);
 
+            laAddSubGroup(p,"proofing_profiles","Proofing Profiles","Soft proofing color profiles","la_proofing_profile",0,0,0,-1,0,0,0,laset_ActiveProofingProfile,lagetstate_ProofingProfile,0,offsetof(LA,ProofingLUTs),0);
+            laAddIntProperty(p,"current_proofing_id","Current Proofing ID","Current soft proofing id in the list",0,0,0,0,0,0,0,0,-1,laget_CurrentProofingID,laset_CurrentProofingID,0,0,0,0,0,0,0,0,0);
+
             laAddFloatProperty(p, "margin_size", "Margin Size", "The global margin factor", 0,0,0,2.0f, 0.1f, 0.02, 1.0f, 0,offsetof(LA, MarginSize), 0,laset_MarginSize, 0,0,0,0,0,0,0,0,0);
             laAddFloatProperty(p, "font_size", "Font Size", "The height of the font related to the row height", 0,0,0,1.0f, 0.1f, 0.02, 0.75, 0,offsetof(LA, FontSize), 0,laset_FontSize, 0,0,0,0,0,0,0,0,0);
             laAddIntProperty(p, "interface_size", "Interface Size", "The height of one row of ui item", 0,0,0,64, 16, 1, 40,0,offsetof(LA, UiRowHeight), 0,laset_UiRowHeight, 0,0,0,0,0,0,0,0,0);
@@ -1884,6 +1926,13 @@ void la_RegisterInternalProps(){
             }
         }
 
+        p = laAddPropertyContainer("la_proofing_profile", "Poofing Profile", "Profile for soft proofing", 0,0,sizeof(laProofingLUT), 0,0,1);{
+            laAddIntProperty(p,"__move","Move Slider","Move Slider",LA_WIDGET_HEIGHT_ADJUSTER,0,0,0,0,0,0,0,0,0,laset_ProofingProfileMove,0,0,0,0,0,0,0,0,LA_UDF_IGNORE);
+            laAddStringProperty(p,"name","Name","Name of the profile",0,0,0,0,1,offsetof(laProofingLUT,Name),0,0,0,0,0);
+            laAddRawProperty(p,"raw_data","Raw Data","Raw data representing the lut",-1,0,lagetraw_ProofingData,lasetraw_ProofingData,0); 
+            laAddOperatorProperty(p,"remove","Remove","Remove this proofing profile","LA_remove_proofing_profile",0,0);
+        }
+
         p = laAddPropertyContainer("la_input_mapping_bundle", "Input Mapping Bundle", "Bundle of input mapping data", 0,0,sizeof(laInputMappingBundle), 0,0,1);{
             laAddSubGroup(p, "mappings","Mappings","Input mappings","la_input_mapping",0,0,0,-1,0,laget_CurrentInputMapping,0,0,0,0,offsetof(laInputMappingBundle,InputMappings),0);
             laAddSubGroup(p, "current","Current Mapping","Current input mapping","la_input_mapping",0,0,0,offsetof(laInputMappingBundle,CurrentInputMapping),laget_FirstInputMapping,0,laget_ListNext,0,0,0,0,LA_UDF_REFER);

+ 42 - 7
resources/la_templates.c

@@ -621,7 +621,13 @@ void laui_DefaultMenuBarActual(laUiList *uil, laPropPack *pp, laPropPack *actins
                 }laEndCondition(uil, uc1);
 #endif
                 laShowItemFull(uil,c,0,"la.windows.output_show_overflow",0,"text=🟩;",0,0)->Flags|=LA_UI_FLAGS_NO_CONFIRM;
-                laShowItemFull(uil,c,0,"la.windows.output_proofing",0,0,0,0)->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_ICON|LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_NO_CONFIRM;
+                laUiItem* hasproof=laOnConditionThat(uil,c,laPropExpression(0,"la.user_preferences.proofing_profiles"));{
+                    laUiItem* proofbtn=laShowItemFull(uil,c,0,"la.windows.output_proofing",0,"icon=🖶",0,0);
+                        proofbtn->Flags|=LA_UI_FLAGS_CYCLE|LA_UI_FLAGS_ICON|LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_NO_CONFIRM;
+                    //laUiItem* enproof=laOnConditionThat(uil,c,laPropExpression(&proofbtn->PP,""));{
+                    //    Should show a name here.
+                    //}laEndCondition(uil,enproof);
+                }laEndCondition(uil,hasproof);
                 laShowItemFull(uil,c,0,"la.windows.use_composing",0,"text=☀",0,0)->Flags|=LA_UI_FLAGS_NO_CONFIRM;
                 laUiItem* cmp=laOnConditionThat(uil,c,laPropExpression(0,"la.windows.use_composing"));{
                     muil = laMakeMenuPageEx(uil, c, "⯆",LA_UI_FLAGS_NO_CONFIRM);{ mc = laFirstColumn(muil);
@@ -1355,6 +1361,19 @@ void laui_Screen(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *U
     laShowItem(uil,cr,This,"description");
     laEndCondition(uil,b);
 }
+void laui_ProofingProfile(laUiList *uil, laPropPack *This, laPropPack *Extra, laColumn *UNUSED, int context){
+    laColumn* c=laFirstColumn(uil); laSplitColumn(uil,c,0.25); laColumn*cl,*cr; cl=laLeftColumn(c,1); cr=laRightColumn(c,0);
+
+    laShowItem(uil,cl,This,"__move");
+    laUiItem* b=laBeginRow(uil,cr,0,0);
+    laUiItem* bb=laOnConditionToggle(uil,cr,0,0,0,0,0);{ strSafeSet(&bb->ExtraInstructions,"icon=🖉;");
+        laShowItem(uil,cr,This,"name")->Expand=1;
+    }laElse(uil,bb);{
+        laShowItemFull(uil,cr,This,"name",LA_WIDGET_STRING_PLAIN,0,0,0)->Expand=1;
+    }laEndCondition(uil,bb);
+    laShowItem(uil,cr,This,"remove")->Flags|=LA_UI_FLAGS_ICON;
+    laEndRow(uil,b);
+}
 
 void laui_UserPreference(laUiList *uil, laPropPack *Base, laPropPack *OperatorInst, laColumn *ExtraColumns, int context){
     laColumn* c = laFirstColumn(uil),*cl,*cr; laSplitColumn(uil,c,0.5);cl=laLeftColumn(c,0);cr=laRightColumn(c,0);
@@ -1416,17 +1435,33 @@ void laui_UserPreference(laUiList *uil, laPropPack *Base, laPropPack *OperatorIn
             laShowItem(muil, mcr, &UP->PP, "color_picker_gamma");
             laShowItem(muil, mcr, &UP->PP, "enable_color_management")->Flags|=LA_UI_FLAGS_CHECKBOX;
 
-#ifndef LAGUI_ANDROID
             laUiItem* bb=laOnConditionThat(muil,mc,laPropExpression(&UP->PP,"enable_color_management"));{
-                laUiItem*bbr=laBeginRow(muil,mc,0,0);
-                laShowLabel(muil, mc, "Per screen config:", 0, 0)->Expand=1;
-                laShowItem(muil,mc,0,"LA_refresh_screens")->Flags|=LA_UI_FLAGS_ICON;
+#ifndef LAGUI_ANDROID
+                laShowSeparator(muil,mc)->Flags|=LA_UI_FLAGS_NO_DECAL;
+                laShowSeparator(muil,mcl);
+                laShowSeparator(muil,mc)->Flags|=LA_UI_FLAGS_NO_DECAL;
+                laShowLabel(muil, mcl, "Per screen config", 0, 0)->Flags|=LA_TEXT_ALIGN_RIGHT;
+                laUiItem*bbr=laBeginRow(muil,mcr,0,0);
                 laShowItemFull(muil, mcr, &UP->PP, "auto_switch_color_space",0,"text=Auto Switch",0,0);
+                laShowItem(muil,mcr,0,"LA_refresh_screens")->Flags|=LA_UI_FLAGS_ICON;
                 laEndRow(muil,bbr);
-                laShowItemFull(muil, mc, &UP->PP, "screens",0,0,laui_Screen,0);
-            }laEndCondition(muil,bb);
+                laShowItemFull(muil, mcr, &UP->PP, "screens",0,0,laui_Screen,0);
 #endif
 
+                laShowSeparator(muil,mc)->Flags|=LA_UI_FLAGS_NO_DECAL;
+                laShowSeparator(muil,mcl);
+                laShowSeparator(muil,mc)->Flags|=LA_UI_FLAGS_NO_DECAL;
+                laShowLabel(muil, mcl, "Soft Proofing", 0, 0)->Flags|=LA_TEXT_ALIGN_RIGHT;
+                laUiItem*bs=laBeginRow(muil,mcr,0,0);
+                laShowItem(muil,mcr,0,"LA_new_proofing_profile");
+                laEndRow(muil,bs);
+                laUiItem* noproof=laOnConditionThat(muil,mc,laNot(laPropExpression(0,"la.user_preferences.proofing_profiles")));{
+                    laShowLabel(muil,mcr,"No icc profiles for soft proofing has been loaded.",0,0)->Flags|=LA_TEXT_LINE_WRAP;
+                }laElse(muil,noproof);{
+                    laShowItemFull(muil, mcr, &UP->PP, "proofing_profiles",0,0,laui_ProofingProfile,0);
+                }laEndCondition(muil,noproof);
+            }laEndCondition(muil,bb);
+
             laShowSeparator(muil, mc);
 
             if(MAIN.InitArgs.HasWorldObjects){

+ 1 - 1
resources/la_translations_es-ES.c

@@ -199,7 +199,7 @@ static const char *entries[]={
 "Thumbnail","Miniatura",
 "Backups","Respaldos",
 "Auto Switch","Auto Conmutar",
-"Per screen config:","Configuración por Monitor:",
+"Per screen config","Configuración por Monitor",
 "Will remove input mapping","Quitará mapeo de entrada",
 "Will remove this key map entry","Quitará este mapeo de tecla de entrada",
 "Select Signal","Seleccione Señal",

+ 1 - 1
resources/la_translations_zh-hans.c

@@ -194,7 +194,7 @@ static const char *entries[]={
 "Thumbnail","缩略图",
 "Backups","备份文件",
 "Auto Switch","自动切换",
-"Per screen config:","针对每个屏幕设置",
+"Per screen config","针对每个屏幕设置",
 "Will remove input mapping","将删除映射",
 "Will remove this key map entry","将删除该映射条目",
 "Select Signal","选择信号",

+ 6 - 3
resources/la_widgets.c

@@ -1457,9 +1457,12 @@ void la_ConditionToggleDraw(laUiItem *ui, int h){
             ui->Type->OperatorType->ParseArgs(0, ui->Instructions, &IconID, buf);
         }
     }
-    if (buf[0]){ sprintf(buf2,"%s%s",transLate(buf),(NoDecal&&(ui->State==LA_UI_NORMAL))?" [...]":""); }
-    if (buf2[0]) tnsDrawStringAuto(buf2, la_UiTextColorState(bt,ui,UseState), ui->L+LA_M-sw, ui->R-LA_M-sw, ui->U-sw, ui->Flags|sf);
-    else tnsDrawStringAuto(ui->State == LA_UI_ACTIVE ? "⯆" : "⯈", la_UiTextColorState(bt,ui,UseState), ui->L+LA_M-sw, ui->R-LA_M-sw, ui->U-sw, ui->Flags|sf);
+    if(IconID){ tnsDrawIcon(IconID,la_UiTextColorState(bt,ui,UseState),ui->L,ui->R,ui->U,ui->Flags|sf); }
+    else{
+        if (buf[0]){ sprintf(buf2,"%s%s",transLate(buf),(NoDecal&&(ui->State==LA_UI_NORMAL))?" [...]":""); }
+        if (buf2[0]) tnsDrawStringAuto(buf2, la_UiTextColorState(bt,ui,UseState), ui->L+LA_M-sw, ui->R-LA_M-sw, ui->U-sw, ui->Flags|sf);
+        else tnsDrawStringAuto(ui->State == LA_UI_ACTIVE ? "⯆" : "⯈", la_UiTextColorState(bt,ui,UseState), ui->L+LA_M-sw, ui->R-LA_M-sw, ui->U-sw, ui->Flags|sf);
+    }
 }
 void la_DrawColumnAdjusterRecursive(int U, int B, laColumn *c, int W, tnsVector4d color, int LeftMost){
     if (c->LS){