2023-06-02 00:20:49 +02:00
# include <QFormLayout>
# include <QVBoxLayout>
# include <QGridLayout>
# include <QGroupBox>
# include <QLineEdit>
# include <QCheckBox>
# include <QPushButton>
# include <QComboBox>
# include <QDialogButtonBox>
# include <QLabel>
# include <QProgressBar>
# include <QProcess>
# include <QTimer>
# include <QJsonDocument>
# include <QJsonArray>
# include <QJsonObject>
2023-05-26 16:17:59 +02:00
# include <zlib.h>
2023-06-02 00:20:49 +02:00
# include "lc_blenderpreferences.h"
# include "lc_application.h"
# include "lc_mainwindow.h"
# include "lc_model.h"
# include "lc_colors.h"
# include "lc_colorpicker.h"
# include "lc_profile.h"
# include "lc_http.h"
2023-05-26 16:17:59 +02:00
# include "lc_zipfile.h"
# include "lc_file.h"
2023-06-02 00:20:49 +02:00
# include "project.h"
# if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
using Qt : : SkipEmptyParts ;
# else
const auto SkipEmptyParts = QString : : SplitBehavior : : SkipEmptyParts ;
# endif
const QLatin1String LineEnding ( " \r \n " ) ;
# define LC_PRODUCTNAME_STR "LeoCAD"
# define LC_BLENDER_ADDON "ImportLDraw"
# define LC_BLENDER_ADDON_MM "ImportLDrawMM"
# define LC_BLENDER_ADDON_FILE "LDrawBlenderRenderAddons.zip"
# define LC_BLENDER_ADDON_INSTALL_FILE "install_blender_ldraw_addons.py"
# define LC_BLENDER_ADDON_CONFIG_FILE "LDrawRendererPreferences.ini"
# define LC_BLENDER_ADDON_PARAMS_FILE "BlenderLDrawParameters.lst"
# define LC_BLENDER_ADDON_REPO_STR "https: //github.com/trevorsandy"
# define LC_BLENDER_ADDON_REPO_API_STR "https: //api.github.com/repos/trevorsandy"
# define LC_BLENDER_ADDON_STR LC_BLENDER_ADDON_REPO_STR " / blenderldrawrender / "
# define LC_BLENDER_ADDON_API_STR LC_BLENDER_ADDON_REPO_API_STR " / blenderldrawrender / "
# define LC_BLENDER_ADDON_LATEST_URL LC_BLENDER_ADDON_API_STR "releases / latest"
# define LC_BLENDER_ADDON_URL LC_BLENDER_ADDON_STR "releases / latest / download / " LC_BLENDER_ADDON_FILE
# define LC_THEME_DARK_PALETTE_MIDLIGHT "#3E3E3E" // 62, 62, 62, 255
# define LC_THEME_DEFAULT_PALETTE_LIGHT "#AEADAC" // 174, 173, 172, 255
# define LC_THEME_DARK_DECORATE_QUOTED_TEXT "#81D4FA" // 129, 212, 250, 255
# define LC_DISABLED_TEXT "#808080" // 128, 128, 128, 255
# define LC_RENDER_IMAGE_MAX_SIZE 32768 // pixels
static QString WhatsThisDescription = QObject : : tr (
" Blender LDraw Addon Settings \n \n "
" You can configure the Blender LDraw addon settings. \n "
" - Blender Executable: set Blender path. On entry, \n "
" %1 will automatically apply the setting and \n "
" attempt the configure the LDraw addon. \n "
" - %1 Blender LDraw Addon: you can update the LDraw \n "
" addon which will downlod the latest addon or apply \n "
" the current addon if the version is the same or newer \n "
" than the online version. \n "
" You can view the standard output log for the update. \n \n "
" - Enabled Addon Modules: check the desired import module. \n "
" The LDraw Import TN import module is the long-standing \n "
" Blender LDraw import addon, while the LDraw Import MM \n "
" addon was recently introduced. The latter addon also \n "
" offer LDraw export functionality. \n "
" The %1 3D Image Render addon is mandatory but if \n "
" no import module is enabled, none of the modules \n "
" will be enabled in Blender so it will not be possible \n "
" to perform an LDraw model import or render. \n \n "
" - LDraw Import Addon Paths: addon paths are specific \n "
" to the enabled addon import module. \n "
" - LDraw Import Addon Settings: addon settings are \n "
" specific to the enabled addon import module. \n "
" - Apply: apply the addon path and setting preferences. \n "
" - Show/Hide Paths: show or hide the addon paths \n "
" display box. \n "
" - Reset: reset the addon path and setting preferences. \n "
" You can select how to reset addon settings. \n "
" The choice is since last apply or system default. \n \n "
" You can see the specific description of each setting \n "
" if you hover over the setting to display its tooltip. \n \n "
" Image Width, Image Height and Render Percentage are \n "
" always updated from the current step model when the \n "
" this dialog is opened. These settngs can be manually \n "
" overridden, Also, when Crop Image is checked the \n "
" current step cropped image width and height is \n "
" calculated and and used \n \n "
" Use the dialogue window scroll bar to access the \n "
" complete selection of addon settings. \n " )
. arg ( QLatin1String ( LC_PRODUCTNAME_STR ) ) ;
lcBlenderPreferences : : BlenderPaths lcBlenderPreferences : : mBlenderPaths [ NUM_PATHS ] ;
lcBlenderPreferences : : BlenderPaths lcBlenderPreferences : : mDefaultPaths [ NUM_PATHS ] =
{
/* Key: MM Key: Value: Label: Tooltip (Description):*/
/* 0 PATH_BLENDER */ { " blenderpath " , " blenderpath " , " " , QObject : : tr ( " Blender Path " ) , QObject : : tr ( " Full file path to Blender application executable " ) } ,
/* 1 PATH_BLENDFILE */ { " blendfile " , " blendfile " , " " , QObject : : tr ( " Blendfile Path " ) , QObject : : tr ( " Full file path to a supplement .blend file - specify to append additional settings " ) } ,
/* 2. PATH_ENVIRONMENT */ { " environmentfile " , " environmentfile " , " " , QObject : : tr ( " Environment Texture Path " ) , QObject : : tr ( " Full file path to .exr environment texture file - specify if not using default bundled in addon " ) } ,
/* 3 PATH_LDCONFIG */ { " customldconfigfile " , " customldconfigfile " , " " , QObject : : tr ( " Custom LDConfig Path " ) , QObject : : tr ( " Full file path to custom LDConfig file - specify if not %1 alternate LDConfig file " ) . arg ( LC_PRODUCTNAME_STR ) } ,
/* 4 PATH_LDRAW */ { " ldrawdirectory " , " ldrawpath " , " " , QObject : : tr ( " LDraw Directory " ) , QObject : : tr ( " Full directory path to the LDraw parts library (download from https://library.ldraw.org) " ) } ,
/* 5 PATH_LSYNTH */ { " lsynthdirectory " , " " , " " , QObject : : tr ( " LSynth Directory " ) , QObject : : tr ( " Full directory path to LSynth primitives - specify if not using default bundled in addon " ) } ,
/* 6 PATH_STUD_LOGO */ { " studlogodirectory " , " " , " " , QObject : : tr ( " Stud Logo Directory " ) , QObject : : tr ( " Full directory path to stud logo primitives - if stud logo enabled, specify if unofficial parts not used or not using default bundled in addon " ) } ,
/* 7 PATH_STUDIO_LDRAW */ { " " , " studioldrawpath " , " " , QObject : : tr ( " Stud.io LDraw Path " ) , QObject : : tr ( " Full filepath to the Stud.io LDraw Parts Library (download from https://www.bricklink.com/v3/studio/download.page) " ) }
} ;
lcBlenderPreferences : : BlenderSettings lcBlenderPreferences : : mBlenderSettings [ NUM_SETTINGS ] ;
lcBlenderPreferences : : BlenderSettings lcBlenderPreferences : : mDefaultSettings [ NUM_SETTINGS ] =
{
/* Key: Value: Label Tooltip (Description)*/
/* 0 LBL_ADD_ENVIRONMENT */ { " addenvironment " , " 1 " , QObject : : tr ( " Add Environment " ) , QObject : : tr ( " Adds a ground plane and environment texture (affects 'Photo-realistic' look only) " ) } ,
/* 1 LBL_ADD_GAPS */ { " gaps " , " 0 " , QObject : : tr ( " Add Part Gap " ) , QObject : : tr ( " Add a small space between each part " ) } ,
/* 2 LBL_BEVEL_EDGES */ { " beveledges " , " 1 " , QObject : : tr ( " Bevel Edges " ) , QObject : : tr ( " Adds a Bevel modifier for rounding off sharp edges " ) } ,
/* 3 LBL_BLENDFILE_TRUSTED */ { " blendfiletrusted " , " 0 " , QObject : : tr ( " Trusted Blend File " ) , QObject : : tr ( " Specify whether to treat the .blend file as being loaded from a trusted source " ) } ,
/* 4 LBL_CROP_IMAGE */ { " cropimage " , " 0 " , QObject : : tr ( " Crop Image " ) , QObject : : tr ( " Crop the image border at opaque content. Requires transparent background set to True " ) } ,
2023-08-11 05:36:51 +02:00
/* 5 LBL_CURVED_WALLS */ { " curvedwalls " , " 1 " , QObject : : tr ( " Curved Walls " ) , QObject : : tr ( " Makes surfaces look slightly concave, for interesting reflections " ) } ,
2023-06-02 00:20:49 +02:00
/* 6 LBL_FLATTEN_HIERARCHY */ { " flattenhierarchy " , " 0 " , QObject : : tr ( " Flatten Hierarchy " ) , QObject : : tr ( " In Scene Outline, all parts are placed directly below the root - there's no tree of submodels " ) } ,
/* 7 LBL_IMPORT_CAMERAS */ { " importcameras " , " 1 " , QObject : : tr ( " Import Cameras " ) , QObject : : tr ( " %1 can specify camera definitions within the ldraw data. Choose to load them or ignore them. " ) . arg ( LC_PRODUCTNAME_STR ) } ,
/* 8 LBL_IMPORT_LIGHTS */ { " importlights " , " 1 " , QObject : : tr ( " Import Lights " ) , QObject : : tr ( " %1 can specify point and sunlight definitions within the ldraw data. Choose to load them or ignore them. " ) . arg ( LC_PRODUCTNAME_STR ) } ,
/* 9 LBL_INSTANCE_STUDS */ { " instancestuds " , " 0 " , QObject : : tr ( " Instance Studs " ) , QObject : : tr ( " Creates a Blender Object for each and every stud (WARNING: can be slow to import and edit in Blender if there are lots of studs) " ) } ,
/*10 LBL_KEEP_ASPECT_RATIO */ { " keepaspectratio " , " 1 " , QObject : : tr ( " Keep Aspect Ratio " ) , QObject : : tr ( " Maintain the aspect ratio when resizing the output image - this attribute is not passed to Blender " ) } ,
/*11 LBL_LINK_PARTS */ { " linkparts " , " 1 " , QObject : : tr ( " Link Like Parts " ) , QObject : : tr ( " Identical parts (of the same type and colour) share the same mesh " ) } ,
/*12 LBL_MINIFIG_HIERARCHY */ { " minifighierarchy " , " 1 " , QObject : : tr ( " Parent Minifigs " ) , QObject : : tr ( " Parts of minifigs are automatically parented to each other in a hierarchy " ) } ,
/*13 LBL_NUMBER_NODES */ { " numbernodes " , " 1 " , QObject : : tr ( " Number Objects " ) , QObject : : tr ( " Each object has a five digit prefix eg. 00001_car. This keeps the list in it's proper order " ) } ,
/*14 LBL_OVERWRITE_IMAGE */ { " overwriteimage " , " 1 " , QObject : : tr ( " Overwrite Image " ) , QObject : : tr ( " Specify whether to overwrite an existing rendered image file " ) } ,
/*15 LBL_OVERWRITE_MATERIALS */ { " overwriteexistingmaterials " , " 0 " , QObject : : tr ( " Use Existing Material " ) , QObject : : tr ( " Overwrite existing material with the same name " ) } ,
/*16 LBL_OVERWRITE_MESHES */ { " overwriteexistingmeshes " , " 0 " , QObject : : tr ( " Use Existing Mesh " ) , QObject : : tr ( " Overwrite existing mesh with the same name " ) } ,
/*17 LBL_POSITION_CAMERA */ { " positioncamera " , " 1 " , QObject : : tr ( " Position Camera " ) , QObject : : tr ( " Position the camera to show the whole model " ) } ,
/*18 LBL_REMOVE_DOUBLES */ { " removedoubles " , " 1 " , QObject : : tr ( " No Duplicate Vertices " ) , QObject : : tr ( " Remove duplicate vertices (recommended) " ) } ,
/*19 LBL_RENDER_WINDOW */ { " renderwindow " , " 1 " , QObject : : tr ( " Display Render Window " ) , QObject : : tr ( " Specify whether to display the render window during Blender user interface image file render " ) } ,
/*10 LBL_USE_ARCHIVE_LIBS */ { " usearchivelibrary " , " 0 " , QObject : : tr ( " Use Archive Libraries " ) , QObject : : tr ( " Add any archive (zip) libraries in the LDraw file path to the library search list " ) } ,
/*21 LBL_SEARCH_ADDL_PATHS */ { " searchadditionalpaths " , " 0 " , QObject : : tr ( " Search Additional Paths " ) , QObject : : tr ( " Specify whether to search additional LDraw paths " ) } ,
/*22 LBL_SMOOTH_SHADING */ { " smoothshading " , " 1 " , QObject : : tr ( " Smooth Shading " ) , QObject : : tr ( " Smooth faces and add an edge-split modifier (recommended) " ) } ,
/*23 LBL_TRANSPARENT_BACKGROUND*/ { " transparentbackground " , " 0 " , QObject : : tr ( " Transparent Background " ) , QObject : : tr ( " Specify whether to render a background (affects 'Photo-realistic look only) " ) } ,
/*24 LBL_UNOFFICIAL_PARTS */ { " useunofficialparts " , " 1 " , QObject : : tr ( " Use Unofficial Parts " ) , QObject : : tr ( " Specify whether to use parts from the LDraw unofficial parts library path " ) } ,
2023-07-07 13:57:00 +02:00
/*25 LBL_USE_LOGO_STUDS */ { " uselogostuds " , " 1 " , QObject : : tr ( " Use Logo Studs " ) , QObject : : tr ( " Shows the LEGO logo on each stud (at the expense of some extra geometry and import time) " ) } ,
2023-06-02 00:20:49 +02:00
/*26 LBL_VERBOSE */ { " verbose " , " 1 " , QObject : : tr ( " Verbose output " ) , QObject : : tr ( " Output all messages while working, else only show warnings and errors " ) } ,
/*27/0 LBL_BEVEL_WIDTH */ { " bevelwidth " , " 0.5 " , QObject : : tr ( " Bevel Width " ) , QObject : : tr ( " Width of the bevelled edges " ) } ,
2023-08-11 05:36:51 +02:00
/*28/1 LBL_CAMERA_BORDER_PERCENT */ { " cameraborderpercentage " , " 5.0 " , QObject : : tr ( " Camera Border Percent " ) , QObject : : tr ( " When positioning the camera, include a (percentage) border leeway around the model in the rendered image " ) } ,
2023-06-02 00:20:49 +02:00
/*29/2 LBL_DEFAULT_COLOUR */ { " defaultcolour " , " 16 " , QObject : : tr ( " Default Colour " ) , QObject : : tr ( " Sets the default part colour using LDraw colour code " ) } ,
2023-08-11 05:36:51 +02:00
/*20/3 LBL_GAPS_SIZE */ { " realgapwidth " , " 0.0002 " , QObject : : tr ( " Gap Width " ) , QObject : : tr ( " Amount of space between each part (default 0.2mm) " ) } ,
2023-06-02 00:20:49 +02:00
/*31/4 LBL_IMAGE_WIDTH */ { " resolutionwidth " , " 800 " , QObject : : tr ( " Image Width " ) , QObject : : tr ( " Sets the rendered image width in pixels - from current step image, label shows config setting. " ) } ,
/*32/5 LBL_IMAGE_HEIGHT */ { " resolutionheight " , " 600 " , QObject : : tr ( " Image Height " ) , QObject : : tr ( " Sets the rendered image height in pixels - from current step image, label shows config setting. " ) } ,
2023-08-11 05:36:51 +02:00
/*33/6 LBL_IMAGE_SCALE */ { " realscale " , " 1.0 " , QObject : : tr ( " Image Scale " ) , QObject : : tr ( " Sets a scale for the model (1.0 = real life scale) " ) } ,
2023-06-02 00:20:49 +02:00
/*34/6 LBL_RENDER_PERCENTAGE */ { " renderpercentage " , " 100 " , QObject : : tr ( " Render Percentage " ) , QObject : : tr ( " Sets the rendered image percentage scale for its pixel resolution - updated from current step, label shows config setting. " ) } ,
/*35/0 LBL_COLOUR_SCHEME */ { " usecolourscheme " , " lgeo " , QObject : : tr ( " Colour Scheme " ) , QObject : : tr ( " Colour scheme options - Realistic (lgeo), Original (LDConfig), Alternate (LDCfgalt), Custom (User Defined) " ) } ,
/*36/1 LBL_FLEX_PARTS_SOURCE */ { " uselsynthparts " , " 1 " , QObject : : tr ( " Flex Parts Source " ) , QObject : : tr ( " Source used to create flexible parts - string, hoses etc. (LDCad, LSynth or both " ) } ,
/*27/2 LBL_LOGO_STUD_VERSION */ { " logostudversion " , " 4 " , QObject : : tr ( " Logo Version " ) , QObject : : tr ( " Which version of the logo to use ('3' (flat), '4' (rounded) or '5' (subtle rounded)) " ) } ,
/*38/3 LBL_LOOK */ { " uselook " , " normal " , QObject : : tr ( " Look " ) , QObject : : tr ( " Photo-realistic or Schematic 'Instruction' look " ) } ,
/*39/4 LBL_POSITION_OBJECT */ { " positionobjectongroundatorigin " , " 1 " , QObject : : tr ( " Position Object " ) , QObject : : tr ( " The object is centred at the origin, and on the ground plane " ) } ,
/*40/5 LBL_RESOLUTION */ { " resolution " , " Standard " , QObject : : tr ( " Resolution " ) , QObject : : tr ( " Resolution of part primitives, ie. how much geometry they have " ) } ,
/*41/6 LBL_RESOLVE_NORMALS */ { " resolvenormals " , " guess " , QObject : : tr ( " Resolve Normals " ) , QObject : : tr ( " Some older LDraw parts have faces with ambiguous normals, this specifies what do do with them " ) }
} ;
lcBlenderPreferences : : ComboItems lcBlenderPreferences : : mComboItems [ NUM_COMBO_ITEMS ] =
{
/* FIRST item set as default Data Item: */
/* 00 LBL_COLOUR_SCHEME */ { " lgeo|ldraw|alt|custom " , QObject : : tr ( " Realistic Colours|Original LDraw Colours|Alternate LDraw Colours|Custom Colours " ) } ,
/* 01 LBL_FLEX_PARTS_SOURCE (t/f) */ { " 1|0|1 " , QObject : : tr ( " LSynth|LDCad|LDCad and LSynth " ) } ,
/* 02 LBL_LOGO_STUD_VERSION */ { " 4|3|5 " , QObject : : tr ( " Rounded(4)|Flattened(3)|Subtle Rounded(5) " ) } ,
/* 03 LBL_LOOK */ { " normal|instructions " , QObject : : tr ( " Photo Realistic|Lego Instructions " ) } ,
/* 04 LBL_POSITION_OBJECT (t/f) */ { " 1|0 " , QObject : : tr ( " Centered At Origin On Ground|Centered At Origin " ) } ,
/* 05 LBL_RESOLUTION */ { " Standard|High|Low " , QObject : : tr ( " Standard Primitives|High Resolution Primitives|Low Resolution Primitives " ) } ,
/* 06 LBL_RESOLVE_NORMALS */ { " guess|double " , QObject : : tr ( " Recalculate Normals|Two Faces Back To Back " ) }
} ;
lcBlenderPreferences : : BlenderSettings lcBlenderPreferences : : mBlenderSettingsMM [ NUM_SETTINGS_MM ] ;
lcBlenderPreferences : : BlenderSettings lcBlenderPreferences : : mDefaultSettingsMM [ NUM_SETTINGS_MM ] =
{
/* Key: Value: Label Tooltip (Description)*/
/* 00 LBL_ADD_ENVIRONMENT_MM */ { " addenvironment " , " 1 " , QObject : : tr ( " Add Environment " ) , QObject : : tr ( " Adds a ground plane and environment texture " ) } ,
/* 01 LBL_BEVEL_EDGES_MM */ { " beveledges " , " 0 " , QObject : : tr ( " Bevel Edgest " ) , QObject : : tr ( " Bevel edges. Can cause some parts to render incorrectly " ) } ,
/* 02 LBL_BLEND_FILE_TRUSTED_MM */ { " blendfiletrusted " , " 0 " , QObject : : tr ( " Trusted Blend File " ) , QObject : : tr ( " Specify whether to treat the .blend file as being loaded from a trusted source " ) } ,
2023-08-11 05:36:51 +02:00
# ifdef Q_OS_LINUX
/* 03 LBL_CASE_SENSITIVE_FILESYSTEM */ { " casesensitivefilesystem " , " 1 " , QObject : : tr ( " Case-sensitive Filesystem " ) , QObject : : tr ( " Filesystem is case sensitive. Defaults to true on Linux. " ) } ,
# else
/* 03 LBL_CASE_SENSITIVE_FILESYSTEM */ { " casesensitivefilesystem " , " 0 " , QObject : : tr ( " Case-sensitive Filesystem " ) , QObject : : tr ( " Filesystem case sensitive defaults to false Windows and MacOS. Set true if LDraw path set to case-sensitive on case-insensitive filesystem. " ) } ,
# endif
/* 04 LBL_CROP_IMAGE_MM */ { " cropimage " , " 0 " , QObject : : tr ( " Crop Image " ) , QObject : : tr ( " Crop the image border at opaque content. Requires transparent background set to True " ) } ,
/* 05 LBL_DISPLAY_LOGO */ { " displaylogo " , " 1 " , QObject : : tr ( " Display Logo " ) , QObject : : tr ( " Display the logo on the stud " ) } ,
/* 06 LBL_IMPORT_CAMERAS_MM */ { " importcameras " , " 1 " , QObject : : tr ( " Import Cameras " ) , QObject : : tr ( " %1 can specify camera definitions within the ldraw data. Choose to load them or ignore them. " ) . arg ( LC_PRODUCTNAME_STR ) } ,
/* 07 LBL_IMPORT_EDGES */ { " importedges " , " 0 " , QObject : : tr ( " Import Edges " ) , QObject : : tr ( " Import LDraw edges as edges " ) } ,
2023-08-19 16:30:01 +02:00
/* 08 LBL_IMPORT_LIGHTS_MM */ { " importlights " , " 1 " , QObject : : tr ( " Import Lights " ) , QObject : : tr ( " %1 can specify point and sunlight definitions within the ldraw data. Choose to load them or ignore them. " ) . arg ( LC_PRODUCTNAME_STR ) } ,
2023-08-11 05:36:51 +02:00
/* 09 LBL_KEEP_ASPECT_RATIO_MM */ { " keepaspectratio " , " 1 " , QObject : : tr ( " Keep Aspect Ratio " ) , QObject : : tr ( " Maintain the aspect ratio when resizing the output image - this attribute is not passed to Blender " ) } ,
/* 10 LBL_MAKE_GAPS */ { " makegaps " , " 1 " , QObject : : tr ( " Make Gaps " ) , QObject : : tr ( " Make small gaps between bricks. A small gap is more realistic " ) } ,
/* 11 LBL_META_BFC */ { " metabfc " , " 1 " , QObject : : tr ( " BFC " ) , QObject : : tr ( " Process LDraw Back Face Culling meta commands " ) } ,
/* 12 LBL_META_CLEAR */ { " metaclear " , " 0 " , QObject : : tr ( " CLEAR Command " ) , QObject : : tr ( " Hides all parts in the timeline up to where this command is encountered " ) } ,
/* 13 LBL_META_GROUP */ { " metagroup " , " 1 " , QObject : : tr ( " GROUP Command " ) , QObject : : tr ( " Process GROUP meta commands " ) } ,
/* 14 LBL_META_PAUSE */ { " metapause " , " 0 " , QObject : : tr ( " PAUSE Command " ) , QObject : : tr ( " Not implemented " ) } ,
/* 15 LBL_META_PRINT_WRITE */ { " metaprintwrite " , " 0 " , QObject : : tr ( " PRINT/WRITE Command " ) , QObject : : tr ( " Prints PRINT/WRITE META commands to the system console. " ) } ,
/* 16 LBL_META_SAVE */ { " metasave " , " 0 " , QObject : : tr ( " SAVE Command " ) , QObject : : tr ( " Not implemented " ) } ,
/* 17 LBL_META_STEP */ { " metastep " , " 0 " , QObject : : tr ( " STEP Command " ) , QObject : : tr ( " Adds a keyframe that shows the part at the moment in the timeline " ) } ,
/* 18 LBL_META_STEP_GROUPS */ { " metastepgroups " , " 0 " , QObject : : tr ( " STEP Groups " ) , QObject : : tr ( " Create collection for individual steps " ) } ,
/* 19 LBL_META_TEXMAP */ { " metatexmap " , " 1 " , QObject : : tr ( " TEXMAP and DATA Command " ) , QObject : : tr ( " Process TEXMAP and DATA meta commands " ) } ,
/* 20 LBL_NO_STUDS */ { " nostuds " , " 0 " , QObject : : tr ( " No Studs " ) , QObject : : tr ( " Don't import studs " ) } ,
/* 21 LBL_OVERWRITE_IMAGE_MM */ { " overwriteimage " , " 1 " , QObject : : tr ( " Overwrite Image " ) , QObject : : tr ( " Specify whether to overwrite an existing rendered image file " ) } ,
/* 22 LBL_POSITION_CAMERA_MM */ { " positioncamera " , " 1 " , QObject : : tr ( " Position Camera " ) , QObject : : tr ( " Position the camera to show the whole model " ) } ,
/* 23 LBL_PARENT_TO_EMPTY */ { " parenttoempty " , " 1 " , QObject : : tr ( " Parent To Empty " ) , QObject : : tr ( " Parent the model to an empty " ) } ,
/* 24 LBL_PREFER_STUDIO */ { " preferstudio " , " 0 " , QObject : : tr ( " Prefer Stud.io Library " ) , QObject : : tr ( " Search for parts in Stud.io library first " ) } ,
/* 25 LBL_PREFER_UNOFFICIAL */ { " preferunofficial " , " 0 " , QObject : : tr ( " Prefer Unofficial Parts " ) , QObject : : tr ( " Search for unofficial parts first " ) } ,
2023-06-02 00:20:49 +02:00
/* 26 LBL_PROFILE */ { " profile " , " 0 " , QObject : : tr ( " Profile " ) , QObject : : tr ( " Profile import performance " ) } ,
/* 27 LBL_RECALCULATE_NORMALS */ { " recalculatenormals " , " 0 " , QObject : : tr ( " Recalculate Normals " ) , QObject : : tr ( " Recalculate normals. Not recommended if BFC processing is active " ) } ,
/* 28 LBL_REMOVE_DOUBLES_MM */ { " removedoubles " , " 1 " , QObject : : tr ( " No Duplicate Vertices " ) , QObject : : tr ( " Merge vertices that are within a certain distance. " ) } ,
/* 29 LBL_RENDER_WINDOW_MM */ { " renderwindow " , " 1 " , QObject : : tr ( " Display Render Window " ) , QObject : : tr ( " Specify whether to display the render window during Blender user interface image file render " ) } ,
/* 30 LBL_SEARCH_ADDL_PATHS_MM */ { " searchadditionalpaths " , " 0 " , QObject : : tr ( " Search Additional Paths " ) , QObject : : tr ( " Specify whether to search additional LDraw paths " ) } ,
/* 31 LBL_SETEND_FRAME */ { " setendframe " , " 1 " , QObject : : tr ( " Set Step End Frame " ) , QObject : : tr ( " Set the end frame to the last step " ) } ,
/* 32 LBL_SET_TIMELINE_MARKERS */ { " settimelinemarkers " , " 0 " , QObject : : tr ( " Set Timeline Markers " ) , QObject : : tr ( " Set timeline markers for meta commands " ) } ,
/* 33 LBL_SHADE_SMOOTH */ { " shadesmooth " , " 1 " , QObject : : tr ( " Shade Smooth " ) , QObject : : tr ( " Use flat or smooth shading for part faces " ) } ,
/* 34 LBL_TRANSPARENT_BACKGROUND_MM */ { " transparentbackground " , " 0 " , QObject : : tr ( " Transparent Background " ) , QObject : : tr ( " Specify whether to render a background " ) } ,
2023-08-11 05:36:51 +02:00
/* 35 LBL_TREAT_SHORTCUT_AS_MODEL */ { " treatshortcutasmodel " , " 0 " , QObject : : tr ( " Treat Shortcuts As Models " ) , QObject : : tr ( " Split shortcut parts into their constituent pieces as if they were models " ) } ,
/* 36 LBL_TRIANGULATE */ { " triangulate " , " 0 " , QObject : : tr ( " Triangulate Faces " ) , QObject : : tr ( " Triangulate all faces " ) } ,
/* 37 LBL_USE_ARCHIVE_LIBRARY_MM */ { " usearchivelibrary " , " 0 " , QObject : : tr ( " Use Archive Libraries " ) , QObject : : tr ( " Add any archive (zip) libraries in the LDraw file path to the library search list " ) } ,
/* 38 LBL_USE_FREESTYLE_EDGES */ { " usefreestyleedges " , " 0 " , QObject : : tr ( " Use Freestyle Edges " ) , QObject : : tr ( " Render LDraw edges using freestyle " ) } ,
/* 39 LBL_VERBOSE_MM */ { " verbose " , " 1 " , QObject : : tr ( " Verbose output " ) , QObject : : tr ( " Output all messages while working, else only show warnings and errors " ) } ,
/* 40/00 LBL_BEVEL_SEGMENTS */ { " bevelsegments " , " 4 " , QObject : : tr ( " Bevel Segments " ) , QObject : : tr ( " Bevel segments " ) } ,
/* 41/01 LBL_BEVEL_WEIGHT */ { " bevelweight " , " 0.3 " , QObject : : tr ( " Bevel Weight " ) , QObject : : tr ( " Bevel weight " ) } ,
/* 42/02 LBL_BEVEL_WIDTH_MM */ { " bevelwidth " , " 0.3 " , QObject : : tr ( " Bevel Width " ) , QObject : : tr ( " Width of the bevelled edges " ) } ,
/* 43/03 LBL_CAMERA_BORDER_PERCENT_MM */ { " cameraborderpercent " , " 5 " , QObject : : tr ( " Camera Border Percent " ) , QObject : : tr ( " When positioning the camera, include a (percentage) border around the model in the render " ) } ,
/* 44/04 LBL_FRAMES_PER_STEP */ { " framesperstep " , " 3 " , QObject : : tr ( " Frames Per Step " ) , QObject : : tr ( " Frames per step " ) } ,
/* 45/05 LBL_GAP_SCALE */ { " gapscale " , " 0.997 " , QObject : : tr ( " Gap Scale " ) , QObject : : tr ( " Scale individual parts by this much to create the gap " ) } ,
/* 46/06 LBL_IMPORT_SCALE */ { " importscale " , " 0.02 " , QObject : : tr ( " Import Scale " ) , QObject : : tr ( " What scale to import at. Full scale is 1.0 and is so huge that it is unwieldy in the viewport " ) } ,
/* 47/07 LBL_MERGE_DISTANCE */ { " mergedistance " , " 0.05 " , QObject : : tr ( " Merge Distance " ) , QObject : : tr ( " Maximum distance between elements to merge " ) } ,
/* 48/08 LBL_RENDER_PERCENTAGE_MM */ { " renderpercentage " , " 100 " , QObject : : tr ( " Render Percentage " ) , QObject : : tr ( " Sets the rendered image percentage scale for its pixel resolution - updated from current step, label shows config setting. " ) } ,
/* 49/09 LBL_RESOLUTION_WIDTH */ { " resolutionwidth " , " 800 " , QObject : : tr ( " Image Width " ) , QObject : : tr ( " Sets the rendered image width in pixels - from current step image, label shows config setting. " ) } ,
/* 50/10 LBL_RESOLUTION_HEIGHT */ { " resolutionheight " , " 600 " , QObject : : tr ( " Image Height " ) , QObject : : tr ( " Sets the rendered image height in pixels - from current step image, label shows config setting. " ) } ,
/* 51/11 LBL_STARTING_STEP_FRAME */ { " startingstepframe " , " 1 " , QObject : : tr ( " Starting Step Frame " ) , QObject : : tr ( " Frame to add the first STEP meta command " ) } ,
/* 52/00 LBL_CHOSEN_LOGO */ { " chosenlogo " , " logo3 " , QObject : : tr ( " Chosen Logo " ) , QObject : : tr ( " Which logo to display. logo and logo2 aren't used and are only included for completeness " ) } ,
/* 53/01 LBL_COLOUR_SCHEME_MM */ { " usecolourscheme " , " lgeo " , QObject : : tr ( " Colour Scheme " ) , QObject : : tr ( " Colour scheme options - Realistic (lgeo), Original (LDConfig), Alternate (LDCfgalt), Custom (User Defined) " ) } ,
/* 54/02 LBL_COLOUR_STRATEGY */ { " colorstrategy " , " material " , QObject : : tr ( " How To Color Parts " ) , QObject : : tr ( " Colour strategy options - Material (Default - use if exporting), Vertex colors (slightly quicker to import) " ) } ,
2023-08-29 22:59:06 +02:00
/* 55/03 LBL_RESOLUTION_MM */ { " resolution " , " Standard " , QObject : : tr ( " Resolution " ) , QObject : : tr ( " Resolution of part primitives, ie. how much geometry they have " ) } ,
2023-09-29 21:49:00 +02:00
/* 56/04 LBL_SMOOTH_TYPE */ { " smoothtype " , " edge_split " , QObject : : tr ( " Smooth Type " ) , QObject : : tr ( " Use either autosmooth or an edge split modifier to smooth part faces " ) }
2023-06-02 00:20:49 +02:00
} ;
lcBlenderPreferences : : ComboItems lcBlenderPreferences : : mComboItemsMM [ NUM_COMBO_ITEMS_MM ] =
{
/* FIRST item set as default Data Item: */
2023-08-19 17:33:57 +02:00
/* 00 LBL_CHOSEN_LOGO */ { " logo3|logo4|logo5 " , QObject : : tr ( " Raised flattened logo geometry(3)|Raised rounded logo geometry(4)|Subtle rounded logo geometry(5) " ) } ,
2023-06-02 00:20:49 +02:00
/* 01 LBL_COLOUR_SCHEME_MM */ { " lgeo|ldraw|alt|custom " , QObject : : tr ( " Realistic Colours|Original LDraw Colours|Alternate LDraw Colours|Custom Colours " ) } ,
2023-08-11 05:36:51 +02:00
/* 02 LBL_COLOUR_STRATEGY */ { " material|vertex_colors " , QObject : : tr ( " Material|Vertex Colors " ) } ,
2023-08-29 22:59:06 +02:00
/* 03 LBL_RESOLUTION_MM */ { " Low|Standard|High " , QObject : : tr ( " Low Resolution Primitives|Standard Primitives|High Resolution Primitives " ) } ,
2023-09-29 21:49:00 +02:00
/* 04 LBL_SMOOTH_TYPE */ { " edge_split|auto_smooth|bmesh_split " , QObject : : tr ( " Smooth part faces with edge split modifier|Auto-smooth part faces|Split during initial mesh processing " ) }
2023-06-02 00:20:49 +02:00
} ;
lcBlenderPreferences * gAddonPreferences ;
lcBlenderPreferencesDialog : : lcBlenderPreferencesDialog ( int Width , int Height , double Scale , QWidget * Parent )
: QDialog ( Parent )
{
setWindowTitle ( tr ( " Blender LDraw Addon Settings " ) ) ;
QVBoxLayout * Layout = new QVBoxLayout ( this ) ;
setLayout ( Layout ) ;
QGroupBox * Box = new QGroupBox ( this ) ;
Layout - > addWidget ( Box ) ;
mPreferences = new lcBlenderPreferences ( Width , Height , Scale , Box ) ;
QDialogButtonBox * ButtonBox ;
ButtonBox = new QDialogButtonBox ( this ) ;
mApplyButton = new QPushButton ( tr ( " Apply " ) , ButtonBox ) ;
mApplyButton - > setToolTip ( tr ( " Apply addon paths and settings preferences " ) ) ;
mApplyButton - > setEnabled ( false ) ;
ButtonBox - > addButton ( mApplyButton , QDialogButtonBox : : ActionRole ) ;
connect ( mApplyButton , SIGNAL ( clicked ( ) ) , this , SLOT ( accept ( ) ) ) ;
mPathsButton = new QPushButton ( tr ( " Hide Paths " ) , ButtonBox ) ;
mPathsButton - > setToolTip ( tr ( " Hide addon path preferences dialog " ) ) ;
ButtonBox - > addButton ( mPathsButton , QDialogButtonBox : : ActionRole ) ;
connect ( mPathsButton , SIGNAL ( clicked ( ) ) , this , SLOT ( ShowPathsGroup ( ) ) ) ;
mResetButton = new QPushButton ( tr ( " Reset " ) , ButtonBox ) ;
mResetButton - > setEnabled ( false ) ;
mResetButton - > setToolTip ( tr ( " Reset addon paths and settings preferences " ) ) ;
ButtonBox - > addButton ( mResetButton , QDialogButtonBox : : ActionRole ) ;
connect ( mResetButton , SIGNAL ( clicked ( ) ) , this , SLOT ( ResetSettings ( ) ) ) ;
ButtonBox - > addButton ( QDialogButtonBox : : Cancel ) ;
connect ( ButtonBox , SIGNAL ( rejected ( ) ) , this , SLOT ( reject ( ) ) ) ;
if ( ! QFileInfo ( lcGetProfileString ( LC_PROFILE_BLENDER_LDRAW_CONFIG_PATH ) ) . isReadable ( ) & & ! lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) . isEmpty ( ) )
mApplyButton - > setEnabled ( true ) ;
connect ( mPreferences , SIGNAL ( SettingChangedSig ( bool ) ) , this , SLOT ( EnableButton ( bool ) ) ) ;
Layout - > addWidget ( ButtonBox ) ;
setMinimumSize ( Box - > sizeHint ( ) . width ( ) + 50 , 500 ) ;
setSizeGripEnabled ( true ) ;
setModal ( true ) ;
}
lcBlenderPreferencesDialog : : ~ lcBlenderPreferencesDialog ( )
{
}
bool lcBlenderPreferencesDialog : : GetBlenderPreferences ( int & Width , int & Height , double & Scale , QWidget * Parent )
{
lcBlenderPreferencesDialog * Dialog = new lcBlenderPreferencesDialog ( Width , Height , Scale , Parent ) ;
bool Ok = Dialog - > exec ( ) = = QDialog : : Accepted ;
if ( Ok )
{
Dialog - > mPreferences - > Apply ( Ok ) ;
Width = Dialog - > mPreferences - > mImageWidth ;
Height = Dialog - > mPreferences - > mImageHeight ;
Scale = Dialog - > mPreferences - > mScale ;
}
return Ok ;
}
void lcBlenderPreferencesDialog : : ShowPathsGroup ( )
{
2023-07-07 00:51:51 +02:00
const QString Display = mPathsButton - > text ( ) . startsWith ( " Hide " ) ? tr ( " Show " ) : tr ( " Hide " ) ;
2023-06-02 00:20:49 +02:00
mPathsButton - > setText ( tr ( " %1 Paths " ) . arg ( Display ) ) ;
mPathsButton - > setToolTip ( tr ( " %1 addon path preferences dialog " ) . arg ( Display ) ) ;
mPreferences - > ShowPathsGroup ( ) ;
}
void lcBlenderPreferencesDialog : : EnableButton ( bool Change )
{
mApplyButton - > setEnabled ( Change ) ;
mResetButton - > setEnabled ( Change ) ;
mPathsButton - > setText ( tr ( " Hide Paths " ) ) ;
mPathsButton - > setToolTip ( tr ( " Hide addon path preferences dialog " ) ) ;
}
void lcBlenderPreferencesDialog : : ResetSettings ( )
{
mPreferences - > ResetSettings ( ) ;
mApplyButton - > setEnabled ( false ) ;
}
void lcBlenderPreferencesDialog : : accept ( )
{
if ( mPreferences - > SettingsModified ( ) )
{
mApplyButton - > setEnabled ( false ) ;
mPreferences - > SaveSettings ( ) ;
QDialog : : accept ( ) ;
} else
QDialog : : reject ( ) ;
}
void lcBlenderPreferencesDialog : : reject ( )
{
if ( mPreferences - > PromptCancel ( ) )
QDialog : : reject ( ) ;
}
lcBlenderPreferences : : lcBlenderPreferences ( int Width , int Height , double Scale , QWidget * Parent )
: QWidget ( Parent )
{
gAddonPreferences = this ;
# ifndef QT_NO_PROCESS
mProcess = nullptr ;
# endif
mImageWidth = Width ;
mImageHeight = Height ;
mScale = Scale ;
mDialogCancelled = false ;
QVBoxLayout * Layout = new QVBoxLayout ( Parent ) ;
if ( Parent )
{
Parent - > setLayout ( Layout ) ;
Parent - > setWhatsThis ( WhatsThisDescription ) ;
}
else
{
setWindowTitle ( tr ( " Blender LDraw Addon Settings " ) ) ;
setLayout ( Layout ) ;
setWhatsThis ( WhatsThisDescription ) ;
}
mContent = new QWidget ( ) ;
mForm = new QFormLayout ( mContent ) ;
mContent - > setLayout ( mForm ) ;
QPalette ReadOnlyPalette = QApplication : : palette ( ) ;
const lcPreferences & Preferences = lcGetPreferences ( ) ;
if ( Preferences . mColorTheme = = lcColorTheme : : Dark )
ReadOnlyPalette . setColor ( QPalette : : Base , QColor ( LC_THEME_DARK_PALETTE_MIDLIGHT ) ) ;
else
ReadOnlyPalette . setColor ( QPalette : : Base , QColor ( LC_THEME_DEFAULT_PALETTE_LIGHT ) ) ;
ReadOnlyPalette . setColor ( QPalette : : Text , QColor ( LC_DISABLED_TEXT ) ) ;
QGroupBox * BlenderExeBox = new QGroupBox ( tr ( " Blender Executable " ) , mContent ) ;
mForm - > addRow ( BlenderExeBox ) ;
mExeGridLayout = new QGridLayout ( BlenderExeBox ) ;
BlenderExeBox - > setLayout ( mExeGridLayout ) ;
mBlenderVersionLabel = new QLabel ( BlenderExeBox ) ;
mExeGridLayout - > addWidget ( mBlenderVersionLabel , 0 , 0 ) ;
mBlenderVersionEdit = new QLineEdit ( BlenderExeBox ) ;
mBlenderVersionEdit - > setPalette ( ReadOnlyPalette ) ;
mBlenderVersionEdit - > setReadOnly ( true ) ;
mExeGridLayout - > addWidget ( mBlenderVersionEdit , 0 , 1 , 1 , 2 ) ;
QLabel * PathLabel = new QLabel ( BlenderExeBox ) ;
mExeGridLayout - > addWidget ( PathLabel , 1 , 0 ) ;
QLineEdit * PathLineEdit = new QLineEdit ( BlenderExeBox ) ;
mExeGridLayout - > addWidget ( PathLineEdit , 1 , 1 ) ;
mPathLineEditList < < PathLineEdit ;
connect ( PathLineEdit , SIGNAL ( editingFinished ( ) ) , this , SLOT ( ConfigureBlenderAddon ( ) ) ) ;
QPushButton * PathBrowseButton = new QPushButton ( tr ( " Browse... " ) , BlenderExeBox ) ;
mExeGridLayout - > addWidget ( PathBrowseButton , 1 , 2 ) ;
mPathBrowseButtonList < < PathBrowseButton ;
connect ( PathBrowseButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( BrowseBlender ( bool ) ) ) ;
QGroupBox * BlenderAddonVersionBox = new QGroupBox ( tr ( " %1 Blender LDraw Addon " ) . arg ( LC_PRODUCTNAME_STR ) , mContent ) ;
mForm - > addRow ( BlenderAddonVersionBox ) ;
mAddonGridLayout = new QGridLayout ( BlenderAddonVersionBox ) ;
BlenderAddonVersionBox - > setLayout ( mAddonGridLayout ) ;
2023-07-30 11:43:13 +02:00
QCheckBox * AddonVersionCheck = new QCheckBox ( tr ( " Prompt to download new addon version when available " ) , BlenderAddonVersionBox ) ;
AddonVersionCheck - > setChecked ( lcGetProfileInt ( LC_PROFILE_BLENDER_ADDON_VERSION_CHECK ) ) ;
QObject : : connect ( AddonVersionCheck , & QCheckBox : : stateChanged , [ ] ( int State )
{
const bool VersionCheck = static_cast < Qt : : CheckState > ( State ) = = Qt : : CheckState : : Checked ;
lcSetProfileInt ( LC_PROFILE_BLENDER_ADDON_VERSION_CHECK , ( int ) VersionCheck ) ;
} ) ;
mAddonGridLayout - > addWidget ( AddonVersionCheck , 0 , 0 , 1 , 4 ) ;
2023-06-02 00:20:49 +02:00
mAddonVersionLabel = new QLabel ( BlenderAddonVersionBox ) ;
2023-07-30 11:43:13 +02:00
mAddonGridLayout - > addWidget ( mAddonVersionLabel , 1 , 0 ) ;
2023-06-02 00:20:49 +02:00
mAddonVersionEdit = new QLineEdit ( BlenderAddonVersionBox ) ;
mAddonVersionEdit - > setToolTip ( tr ( " %1 Blender LDraw import and image renderer addon " ) . arg ( LC_PRODUCTNAME_STR ) ) ;
mAddonVersionEdit - > setPalette ( ReadOnlyPalette ) ;
mAddonVersionEdit - > setReadOnly ( true ) ;
2023-07-30 11:43:13 +02:00
mAddonGridLayout - > addWidget ( mAddonVersionEdit , 1 , 1 ) ;
2023-06-02 00:20:49 +02:00
mAddonGridLayout - > setColumnStretch ( 1 , 1 /*1 is greater than 0 (default)*/ ) ;
mAddonUpdateButton = new QPushButton ( tr ( " Update " ) , BlenderAddonVersionBox ) ;
mAddonUpdateButton - > setToolTip ( tr ( " Update %1 Blender LDraw addon " ) . arg ( LC_PRODUCTNAME_STR ) ) ;
2023-07-30 11:43:13 +02:00
mAddonGridLayout - > addWidget ( mAddonUpdateButton , 1 , 2 ) ;
2023-06-02 00:20:49 +02:00
connect ( mAddonUpdateButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( UpdateBlenderAddon ( ) ) ) ;
mAddonStdOutButton = new QPushButton ( tr ( " Output... " ) , BlenderAddonVersionBox ) ;
mAddonStdOutButton - > setToolTip ( tr ( " Open the standrd output log " ) ) ;
mAddonStdOutButton - > setEnabled ( false ) ;
2023-07-30 11:43:13 +02:00
mAddonGridLayout - > addWidget ( mAddonStdOutButton , 1 , 3 ) ;
2023-06-02 00:20:49 +02:00
connect ( mAddonStdOutButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( GetStandardOutput ( ) ) ) ;
mModulesBox = new QGroupBox ( tr ( " Enabled Addon Modules " ) , mContent ) ;
QHBoxLayout * ModulesLayout = new QHBoxLayout ( mModulesBox ) ;
mModulesBox - > setLayout ( ModulesLayout ) ;
2023-07-30 11:43:13 +02:00
mAddonGridLayout - > addWidget ( mModulesBox , 2 , 0 , 1 , 4 ) ;
2023-06-02 00:20:49 +02:00
mImportActBox = new QCheckBox ( tr ( " LDraw Import TN " ) , mModulesBox ) ;
mImportActBox - > setToolTip ( tr ( " Enable addon import module (adapted from LDraw Import by Toby Nelson) in Blender " ) ) ;
ModulesLayout - > addWidget ( mImportActBox ) ;
connect ( mImportActBox , SIGNAL ( clicked ( bool ) ) , this , SLOT ( EnableImportModule ( ) ) ) ;
mImportMMActBox = new QCheckBox ( tr ( " LDraw Import MM " ) , mModulesBox ) ;
mImportMMActBox - > setToolTip ( tr ( " Enable addon import module (adapted from LDraw Import by Matthew Morrison) in Blender " ) ) ;
ModulesLayout - > addWidget ( mImportMMActBox ) ;
connect ( mImportMMActBox , SIGNAL ( clicked ( bool ) ) , this , SLOT ( EnableImportModule ( ) ) ) ;
mRenderActBox = new QCheckBox ( tr ( " %1 Image Render " ) . arg ( LC_PRODUCTNAME_STR ) , mModulesBox ) ;
mRenderActBox - > setToolTip ( tr ( " Addon image render module in Blender " ) ) ;
mRenderActBox - > setEnabled ( false ) ;
ModulesLayout - > addWidget ( mRenderActBox ) ;
LoadSettings ( ) ;
mConfigured = ! lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) . isEmpty ( ) ;
const int CtlIdx = PATH_BLENDER ;
PathLabel - > setText ( mBlenderPaths [ CtlIdx ] . label ) ;
PathLabel - > setToolTip ( mBlenderPaths [ CtlIdx ] . tooltip ) ;
PathLineEdit - > setText ( mBlenderPaths [ CtlIdx ] . value ) ;
PathLineEdit - > setToolTip ( mBlenderPaths [ CtlIdx ] . tooltip ) ;
if ( mAddonVersion . isEmpty ( ) )
{
mModulesBox - > setEnabled ( false ) ;
mAddonUpdateButton - > setEnabled ( false ) ;
mImportActBox - > setChecked ( true ) ; // default addon module
}
else
{
mAddonVersionEdit - > setText ( mAddonVersion ) ;
mRenderActBox - > setChecked ( true ) ;
mImportActBox - > setChecked ( lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) = = QLatin1String ( " TN " ) ) ;
mImportMMActBox - > setChecked ( lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) = = QLatin1String ( " MM " ) ) ;
}
QString VersionTextColour = QApplication : : palette ( ) . text ( ) . color ( ) . name ( ) , AddonTextColour ;
QString VersionText = tr ( " Blender " ) , AddonText = tr ( " Blender Addon " ) ;
if ( mConfigured )
{
AddonTextColour = VersionTextColour ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
mBlenderVersionEdit - > setVisible ( true ) ;
}
else
{
2023-07-07 00:51:51 +02:00
const QString TextColour = Preferences . mColorTheme = = lcColorTheme : : Dark ? QLatin1String ( LC_THEME_DARK_DECORATE_QUOTED_TEXT ) : QLatin1String ( " blue " ) ;
2023-06-02 00:20:49 +02:00
bool BlenderConfigured = ! lcGetProfileString ( LC_PROFILE_BLENDER_PATH ) . isEmpty ( ) ;
if ( ! BlenderConfigured )
{
VersionText = tr ( " Blender not configured. " ) ;
VersionTextColour = TextColour ;
}
else
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
if ( QFileInfo ( QString ( " %1/Blender/%2 " ) . arg ( mDataDir ) . arg ( LC_BLENDER_ADDON_FILE ) ) . isReadable ( ) )
{
mModulesBox - > setEnabled ( false ) ;
mImportActBox - > setChecked ( true ) ;
mAddonUpdateButton - > setEnabled ( true ) ;
if ( BlenderConfigured )
AddonText = tr ( " Addon not configured - Update. " ) ;
else
AddonText = tr ( " Addon not configured. " ) ;
AddonTextColour = TextColour ;
}
}
mAddonVersionEdit - > setVisible ( ! mAddonVersion . isEmpty ( ) ) ;
mBlenderVersionLabel - > setStyleSheet ( QString ( " QLabel { color : %1; } " ) . arg ( VersionTextColour ) ) ;
mAddonVersionLabel - > setStyleSheet ( QString ( " QLabel { color : %1; } " ) . arg ( AddonTextColour ) ) ;
mBlenderVersionLabel - > setText ( VersionText ) ;
mAddonVersionLabel - > setText ( AddonText ) ;
if ( mImportMMActBox - > isChecked ( ) )
InitPathsAndSettingsMM ( ) ;
else
InitPathsAndSettings ( ) ;
QScrollArea * ScrollArea = new QScrollArea ( this ) ;
ScrollArea - > setWidgetResizable ( true ) ;
ScrollArea - > setWidget ( mContent ) ;
Layout - > addWidget ( ScrollArea ) ;
}
lcBlenderPreferences : : ~ lcBlenderPreferences ( )
{
gAddonPreferences = nullptr ;
}
void lcBlenderPreferences : : ClearGroupBox ( QGroupBox * GroupBox )
{
int Row = - 1 ;
QFormLayout : : ItemRole ItemRole = QFormLayout : : SpanningRole ;
mForm - > getWidgetPosition ( GroupBox , & Row , & ItemRole ) ;
if ( Row = = - 1 | | ItemRole ! = QFormLayout : : SpanningRole ) return ;
QLayoutItem * GroupBoxIitem = mForm - > itemAt ( Row , ItemRole ) ;
mForm - > removeItem ( GroupBoxIitem ) ;
QWidget * WidgetItem = GroupBoxIitem - > widget ( ) ;
if ( WidgetItem )
{
if ( GroupBox = = mPathsBox )
{
delete mPathsBox ;
mPathsBox = nullptr ;
}
else if ( GroupBox = = mSettingsBox )
{
delete mSettingsBox ;
mSettingsBox = nullptr ;
}
}
delete GroupBoxIitem ;
}
void lcBlenderPreferences : : InitPathsAndSettings ( )
{
if ( ! NumSettings ( ) )
LoadSettings ( ) ;
// Paths
ClearGroupBox ( mPathsBox ) ;
mPathsBox = new QGroupBox ( mContent ) ;
mPathsBox - > setTitle ( tr ( " LDraw Import TN Addon Paths " ) ) ;
mPathsGridLayout = new QGridLayout ( mPathsBox ) ;
mPathsBox - > setLayout ( mPathsGridLayout ) ;
mForm - > addRow ( mPathsBox ) ;
for ( int CtlIdx = 1 /*skip blender executable*/ ; CtlIdx < NumPaths ( ) ; + + CtlIdx )
{
int ColumnIdx = CtlIdx - 1 ; // adjust for skipping first item - blender executable
bool IsVisible = CtlIdx ! = PATH_STUDIO_LDRAW ;
QLabel * PathLabel = new QLabel ( mBlenderPaths [ CtlIdx ] . label , mPathsBox ) ;
PathLabel - > setToolTip ( mBlenderPaths [ CtlIdx ] . tooltip ) ;
mPathsGridLayout - > addWidget ( PathLabel , ColumnIdx , 0 ) ;
PathLabel - > setVisible ( IsVisible ) ;
QLineEdit * PathLineEdit = new QLineEdit ( mPathsBox ) ;
PathLineEdit - > setProperty ( " ControlID " , QVariant ( CtlIdx ) ) ;
PathLineEdit - > setText ( mBlenderPaths [ CtlIdx ] . value ) ;
PathLineEdit - > setToolTip ( mBlenderPaths [ CtlIdx ] . tooltip ) ;
if ( mPathLineEditList . size ( ) > CtlIdx )
mPathLineEditList . replace ( CtlIdx , PathLineEdit ) ;
else
mPathLineEditList < < PathLineEdit ;
mPathsGridLayout - > addWidget ( PathLineEdit , ColumnIdx , 1 ) ;
PathLineEdit - > setVisible ( IsVisible ) ;
QPushButton * PathBrowseButton = new QPushButton ( tr ( " Browse... " ) , mPathsBox ) ;
if ( mPathBrowseButtonList . size ( ) > CtlIdx )
mPathBrowseButtonList . replace ( CtlIdx , PathBrowseButton ) ;
else
mPathBrowseButtonList < < PathBrowseButton ;
mPathsGridLayout - > addWidget ( PathBrowseButton , ColumnIdx , 2 ) ;
PathBrowseButton - > setVisible ( IsVisible ) ;
if ( IsVisible )
{
connect ( PathBrowseButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( BrowseBlender ( bool ) ) ) ;
connect ( PathLineEdit , SIGNAL ( editingFinished ( ) ) , this , SLOT ( PathChanged ( ) ) ) ;
}
}
mPathsBox - > setEnabled ( mConfigured ) ;
// Settings
ClearGroupBox ( mSettingsBox ) ;
mSettingsBox = new QGroupBox ( mContent ) ;
mSettingsSubform = new QFormLayout ( mSettingsBox ) ;
mSettingsBox - > setLayout ( mSettingsSubform ) ;
mForm - > addRow ( mSettingsBox ) ;
mSettingsBox - > setTitle ( tr ( " LDraw Import TN Addon Settings " ) ) ;
mSettingLabelList . clear ( ) ;
mCheckBoxList . clear ( ) ;
mLineEditList . clear ( ) ;
mComboBoxList . clear ( ) ;
int ComboBoxItemsIndex = 0 ;
for ( int LblIdx = 0 ; LblIdx < NumSettings ( ) ; LblIdx + + )
{
QLabel * Label = new QLabel ( mSettingsBox ) ;
Label - > setText ( mBlenderSettings [ LblIdx ] . label ) ;
Label - > setToolTip ( mBlenderSettings [ LblIdx ] . tooltip ) ;
mSettingLabelList < < Label ;
if ( LblIdx < LBL_BEVEL_WIDTH )
{ // QCheckBoxes
QCheckBox * CheckBox = new QCheckBox ( mSettingsBox ) ;
CheckBox - > setProperty ( " ControlID " , QVariant ( LblIdx ) ) ;
CheckBox - > setChecked ( mBlenderSettings [ LblIdx ] . value . toInt ( ) ) ;
CheckBox - > setToolTip ( mBlenderSettings [ LblIdx ] . tooltip ) ;
if ( LblIdx = = LBL_CROP_IMAGE )
connect ( CheckBox , SIGNAL ( toggled ( bool ) ) , this , SLOT ( SetModelSize ( bool ) ) ) ;
else
connect ( CheckBox , SIGNAL ( clicked ( ) ) , this , SLOT ( SettingChanged ( ) ) ) ;
mCheckBoxList < < CheckBox ;
mSettingsSubform - > addRow ( Label , CheckBox ) ;
}
else if ( LblIdx < LBL_COLOUR_SCHEME )
{ // QLineEdits
QLineEdit * LineEdit = new QLineEdit ( mSettingsBox ) ;
LineEdit - > setProperty ( " ControlID " , QVariant ( LblIdx ) ) ;
if ( LblIdx = = LBL_IMAGE_WIDTH | | LblIdx = = LBL_IMAGE_HEIGHT )
{
connect ( LineEdit , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
LineEdit - > setValidator ( new QIntValidator ( 16 , LC_RENDER_IMAGE_MAX_SIZE ) ) ;
}
else if ( LblIdx = = LBL_DEFAULT_COLOUR )
{
LineEdit - > setReadOnly ( true ) ;
LineEdit - > setStyleSheet ( " Text-align:left " ) ;
mDefaultColourEditAction = LineEdit - > addAction ( QIcon ( ) , QLineEdit : : TrailingPosition ) ;
connect ( mDefaultColourEditAction , SIGNAL ( triggered ( bool ) ) , this , SLOT ( ColorButtonClicked ( bool ) ) ) ;
}
else
{
LineEdit - > setText ( mBlenderSettings [ LblIdx ] . value ) ;
if ( LblIdx = = LBL_IMAGE_SCALE )
LineEdit - > setValidator ( new QDoubleValidator ( 0.01 , 10.0 , 2 ) ) ;
else if ( LblIdx = = LBL_RENDER_PERCENTAGE | | LblIdx = = LBL_CAMERA_BORDER_PERCENT )
LineEdit - > setValidator ( new QIntValidator ( 1 , 1000 ) ) ;
else
LineEdit - > setValidator ( new QDoubleValidator ( 0.01 , 100.0 , 2 ) ) ;
connect ( LineEdit , SIGNAL ( textEdited ( const QString & ) ) , this , SLOT ( SettingChanged ( const QString & ) ) ) ;
}
LineEdit - > setToolTip ( mBlenderSettings [ LblIdx ] . tooltip ) ;
mLineEditList < < LineEdit ;
if ( LblIdx = = LBL_DEFAULT_COLOUR )
SetDefaultColor ( lcGetColorIndex ( mBlenderSettings [ LBL_DEFAULT_COLOUR ] . value . toInt ( ) ) ) ;
mSettingsSubform - > addRow ( Label , LineEdit ) ;
}
else
{ // QComboBoxes
QComboBox * ComboBox = new QComboBox ( mSettingsBox ) ;
ComboBox - > setProperty ( " ControlID " , QVariant ( LblIdx ) ) ;
2023-07-07 00:51:51 +02:00
const QString Value = mBlenderSettings [ LblIdx ] . value ;
2023-06-02 00:20:49 +02:00
QStringList const DataList = mComboItems [ ComboBoxItemsIndex ] . dataList . split ( " | " ) ;
QStringList const ItemList = mComboItems [ ComboBoxItemsIndex ] . itemList . split ( " | " ) ;
ComboBox - > addItems ( ItemList ) ;
for ( int CtlIdx = 0 ; CtlIdx < ComboBox - > count ( ) ; CtlIdx + + )
ComboBox - > setItemData ( CtlIdx , DataList . at ( CtlIdx ) ) ;
ComboBox - > setToolTip ( mBlenderSettings [ LblIdx ] . tooltip ) ;
int CurrentIndex = int ( ComboBox - > findData ( QVariant : : fromValue ( Value ) ) ) ;
ComboBox - > setCurrentIndex ( CurrentIndex ) ;
if ( LblIdx = = LBL_COLOUR_SCHEME )
connect ( ComboBox , SIGNAL ( currentIndexChanged ( int ) ) , this , SLOT ( ValidateColourScheme ( int ) ) ) ;
else
connect ( ComboBox , SIGNAL ( currentIndexChanged ( int ) ) , this , SLOT ( SettingChanged ( int ) ) ) ;
mComboBoxList < < ComboBox ;
ComboBoxItemsIndex + + ;
mSettingsSubform - > addRow ( Label , ComboBox ) ;
}
}
SetModelSize ( ) ;
if ( ! mSettingsSubform - > rowCount ( ) )
mSettingsSubform = nullptr ;
mSettingsBox - > setEnabled ( mConfigured ) ;
}
void lcBlenderPreferences : : InitPathsAndSettingsMM ( )
{
if ( ! NumSettingsMM ( ) )
LoadSettings ( ) ;
// Paths
ClearGroupBox ( mPathsBox ) ;
mPathsBox = new QGroupBox ( mContent ) ;
mPathsBox - > setTitle ( tr ( " LDraw Import MM Addon Paths " ) ) ;
mPathsGridLayout = new QGridLayout ( mPathsBox ) ;
mPathsBox - > setLayout ( mPathsGridLayout ) ;
mForm - > addRow ( mPathsBox ) ;
for ( int CtlIdx = 1 /*skip blender executable*/ ; CtlIdx < NumPaths ( ) ; + + CtlIdx )
{
int ColumnIdx = CtlIdx - 1 ; // adjust for skipping first item - blender executable
bool IsVisible = CtlIdx ! = PATH_LSYNTH & & CtlIdx ! = PATH_STUD_LOGO ;
QLabel * PathLabel = new QLabel ( mBlenderPaths [ CtlIdx ] . label , mPathsBox ) ;
PathLabel - > setToolTip ( mBlenderPaths [ CtlIdx ] . tooltip ) ;
mPathsGridLayout - > addWidget ( PathLabel , ColumnIdx , 0 ) ;
PathLabel - > setVisible ( IsVisible ) ;
QLineEdit * PathLineEdit = new QLineEdit ( mPathsBox ) ;
PathLineEdit - > setProperty ( " ControlID " , QVariant ( CtlIdx ) ) ;
PathLineEdit - > setText ( mBlenderPaths [ CtlIdx ] . value ) ;
PathLineEdit - > setToolTip ( mBlenderPaths [ CtlIdx ] . tooltip ) ;
if ( mPathLineEditList . size ( ) > CtlIdx )
mPathLineEditList . replace ( CtlIdx , PathLineEdit ) ;
else
mPathLineEditList < < PathLineEdit ;
mPathsGridLayout - > addWidget ( PathLineEdit , ColumnIdx , 1 ) ;
PathLineEdit - > setVisible ( IsVisible ) ;
QPushButton * PathBrowseButton = new QPushButton ( tr ( " Browse... " ) , mPathsBox ) ;
if ( mPathBrowseButtonList . size ( ) > CtlIdx )
mPathBrowseButtonList . replace ( CtlIdx , PathBrowseButton ) ;
else
mPathBrowseButtonList < < PathBrowseButton ;
mPathsGridLayout - > addWidget ( PathBrowseButton , ColumnIdx , 2 ) ;
PathBrowseButton - > setVisible ( IsVisible ) ;
if ( IsVisible )
{
connect ( PathBrowseButton , SIGNAL ( clicked ( bool ) ) , this , SLOT ( BrowseBlender ( bool ) ) ) ;
connect ( PathLineEdit , SIGNAL ( editingFinished ( ) ) , this , SLOT ( PathChanged ( ) ) ) ;
}
}
mPathsBox - > setEnabled ( mConfigured ) ;
// Settings
ClearGroupBox ( mSettingsBox ) ;
mSettingsBox = new QGroupBox ( mContent ) ;
mSettingsSubform = new QFormLayout ( mSettingsBox ) ;
mSettingsBox - > setLayout ( mSettingsSubform ) ;
mForm - > addRow ( mSettingsBox ) ;
mSettingsBox - > setTitle ( tr ( " LDraw Import MM Addon Settings " ) ) ;
mSettingLabelList . clear ( ) ;
mCheckBoxList . clear ( ) ;
mLineEditList . clear ( ) ;
mComboBoxList . clear ( ) ;
int ComboBoxItemsIndex = 0 ;
for ( int LblIdx = 0 ; LblIdx < NumSettingsMM ( ) ; LblIdx + + )
{
QLabel * Label = new QLabel ( mSettingsBox ) ;
Label - > setText ( mBlenderSettingsMM [ LblIdx ] . label ) ;
Label - > setToolTip ( mBlenderSettingsMM [ LblIdx ] . tooltip ) ;
mSettingLabelList < < Label ;
if ( LblIdx < LBL_BEVEL_SEGMENTS )
{ // QCheckBoxes
QCheckBox * CheckBox = new QCheckBox ( mSettingsBox ) ;
CheckBox - > setProperty ( " ControlID " , QVariant ( LblIdx ) ) ;
CheckBox - > setChecked ( mBlenderSettingsMM [ LblIdx ] . value . toInt ( ) ) ;
CheckBox - > setToolTip ( mBlenderSettingsMM [ LblIdx ] . tooltip ) ;
if ( LblIdx = = LBL_CROP_IMAGE_MM )
connect ( CheckBox , SIGNAL ( toggled ( bool ) ) , this , SLOT ( SetModelSize ( bool ) ) ) ;
else
connect ( CheckBox , SIGNAL ( clicked ( ) ) , this , SLOT ( SettingChanged ( ) ) ) ;
mCheckBoxList < < CheckBox ;
mSettingsSubform - > addRow ( Label , CheckBox ) ;
}
else if ( LblIdx < LBL_CHOSEN_LOGO )
{ // QLineEdits
QLineEdit * LineEdit = new QLineEdit ( mSettingsBox ) ;
LineEdit - > setProperty ( " ControlID " , QVariant ( LblIdx ) ) ;
if ( LblIdx = = LBL_RESOLUTION_WIDTH | | LblIdx = = LBL_RESOLUTION_HEIGHT )
{
connect ( LineEdit , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
LineEdit - > setValidator ( new QIntValidator ( 16 , LC_RENDER_IMAGE_MAX_SIZE ) ) ;
}
else
{
LineEdit - > setText ( mBlenderSettingsMM [ LblIdx ] . value ) ;
if ( LblIdx = = LBL_IMPORT_SCALE )
LineEdit - > setValidator ( new QDoubleValidator ( 0.01 , 10.0 , 2 ) ) ;
else if ( LblIdx = = LBL_RENDER_PERCENTAGE_MM | | LblIdx = = LBL_CAMERA_BORDER_PERCENT_MM )
LineEdit - > setValidator ( new QIntValidator ( 1 , 1000 ) ) ;
else if ( LblIdx = = LBL_GAP_SCALE | | LblIdx = = LBL_MERGE_DISTANCE )
LineEdit - > setValidator ( new QDoubleValidator ( 0.001 , 100.0 , 3 ) ) ;
else if ( LblIdx = = LBL_BEVEL_WEIGHT | | LblIdx = = LBL_BEVEL_WIDTH_MM )
LineEdit - > setValidator ( new QDoubleValidator ( 0.0 , 10.0 , 1 ) ) ;
else
LineEdit - > setValidator ( new QIntValidator ( 1 , LC_RENDER_IMAGE_MAX_SIZE ) ) ;
connect ( LineEdit , SIGNAL ( textEdited ( const QString & ) ) , this , SLOT ( SettingChanged ( const QString & ) ) ) ;
}
LineEdit - > setToolTip ( mBlenderSettingsMM [ LblIdx ] . tooltip ) ;
mLineEditList < < LineEdit ;
mSettingsSubform - > addRow ( Label , LineEdit ) ;
}
else
{ // QComboBoxes
QComboBox * ComboBox = new QComboBox ( mSettingsBox ) ;
ComboBox - > setProperty ( " ControlID " , QVariant ( LblIdx ) ) ;
2023-07-07 00:51:51 +02:00
const QString Value = mBlenderSettingsMM [ LblIdx ] . value ;
2023-06-02 00:20:49 +02:00
QStringList const DataList = mComboItemsMM [ ComboBoxItemsIndex ] . dataList . split ( " | " ) ;
QStringList const ItemList = mComboItemsMM [ ComboBoxItemsIndex ] . itemList . split ( " | " ) ;
ComboBox - > addItems ( ItemList ) ;
for ( int CtlIdx = 0 ; CtlIdx < ComboBox - > count ( ) ; CtlIdx + + )
ComboBox - > setItemData ( CtlIdx , DataList . at ( CtlIdx ) ) ;
ComboBox - > setToolTip ( mBlenderSettingsMM [ LblIdx ] . tooltip ) ;
int CurrentIndex = int ( ComboBox - > findData ( QVariant : : fromValue ( Value ) ) ) ;
ComboBox - > setCurrentIndex ( CurrentIndex ) ;
if ( LblIdx = = LBL_COLOUR_SCHEME_MM )
connect ( ComboBox , SIGNAL ( currentIndexChanged ( int ) ) , this , SLOT ( ValidateColourScheme ( int ) ) ) ;
else
connect ( ComboBox , SIGNAL ( currentIndexChanged ( int ) ) , this , SLOT ( SettingChanged ( int ) ) ) ;
mComboBoxList < < ComboBox ;
ComboBoxItemsIndex + + ;
mSettingsSubform - > addRow ( Label , ComboBox ) ;
}
}
SetModelSize ( ) ;
if ( ! mSettingsSubform - > rowCount ( ) )
mSettingsSubform = nullptr ;
mSettingsBox - > setEnabled ( mConfigured ) ;
}
void lcBlenderPreferences : : UpdateBlenderAddon ( )
{
mAddonUpdateButton - > setEnabled ( false ) ;
disconnect ( mPathLineEditList [ PATH_BLENDER ] , SIGNAL ( editingFinished ( ) ) , this , SLOT ( ConfigureBlenderAddon ( ) ) ) ;
ConfigureBlenderAddon ( sender ( ) = = mPathBrowseButtonList [ PATH_BLENDER ] ,
sender ( ) = = mAddonUpdateButton ) ;
connect ( mPathLineEditList [ PATH_BLENDER ] , SIGNAL ( editingFinished ( ) ) , this , SLOT ( ConfigureBlenderAddon ( ) ) ) ;
}
void lcBlenderPreferences : : ConfigureBlenderAddon ( bool TestBlender , bool AddonUpdate , bool ModuleChange )
{
mProgressBar = nullptr ;
2023-07-07 00:51:51 +02:00
const QString BlenderExe = QDir : : toNativeSeparators ( mPathLineEditList [ PATH_BLENDER ] - > text ( ) ) ;
2023-06-02 00:20:49 +02:00
if ( BlenderExe . isEmpty ( ) )
{
mBlenderVersion . clear ( ) ;
mConfigured = false ;
StatusUpdate ( false , true ) ;
mAddonUpdateButton - > setEnabled ( mConfigured ) ;
mPathsBox - > setEnabled ( mConfigured ) ;
mSettingsBox - > setEnabled ( mConfigured ) ;
return ;
}
if ( QFileInfo ( BlenderExe ) . isReadable ( ) )
{
enum ProcEnc
2023-07-07 00:51:51 +02:00
{
PR_OK , PR_FAIL , PR_WAIT , PR_INSTALL , PR_TEST
} ;
const QString BlenderDir = QDir : : toNativeSeparators ( QString ( " %1/Blender " ) . arg ( mDataDir ) ) ;
const QString BlenderConfigDir = QString ( " %1/setup/addon_setup/config " ) . arg ( BlenderDir ) ;
const QString BlenderAddonDir = QDir : : toNativeSeparators ( QString ( " %1/addons " ) . arg ( BlenderDir ) ) ;
const QString BlenderExeCompare = QDir : : toNativeSeparators ( lcGetProfileString ( LC_PROFILE_BLENDER_PATH ) ) . toLower ( ) ;
const QString BlenderInstallFile = QDir : : toNativeSeparators ( QString ( " %1/%2 " ) . arg ( BlenderDir ) . arg ( LC_BLENDER_ADDON_INSTALL_FILE ) ) ;
const QString BlenderTestString = QLatin1String ( " ###TEST_BLENDER### " ) ;
2023-06-02 00:20:49 +02:00
QByteArray AddonPathsAndModuleNames ;
QString Message , ShellProgram ;
QStringList Arguments ;
ProcEnc Result = PR_OK ;
QFile Script ;
bool NewBlenderExe = BlenderExeCompare ! = BlenderExe . toLower ( ) ;
if ( mConfigured & & ! AddonUpdate & & ! ModuleChange & & ! NewBlenderExe )
return ;
auto ProcessCommand = [ & ] ( ProcEnc Action )
{
mProcess = new QProcess ( ) ;
QString ProcessAction = tr ( " addon install " ) ;
if ( Action = = PR_INSTALL )
{
connect ( mProcess , SIGNAL ( readyReadStandardOutput ( ) ) , this , SLOT ( ReadStdOut ( ) ) ) ;
2023-07-07 00:51:51 +02:00
const QString & LdrawLibPath = QFileInfo ( lcGetProfileString ( LC_PROFILE_PARTS_LIBRARY ) ) . absolutePath ( ) ;
2023-06-02 00:20:49 +02:00
QStringList SystemEnvironment = QProcess : : systemEnvironment ( ) ;
SystemEnvironment . prepend ( " LDRAW_DIRECTORY= " + LdrawLibPath ) ;
SystemEnvironment . prepend ( " ADDONS_TO_LOAD= " + AddonPathsAndModuleNames ) ;
mProcess - > setEnvironment ( SystemEnvironment ) ;
}
else
{
ProcessAction = tr ( " test " ) ;
disconnect ( & mUpdateTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( Update ( ) ) ) ;
}
mProcess - > setWorkingDirectory ( BlenderDir ) ;
mProcess - > setStandardErrorFile ( QString ( " %1/stderr-blender-addon-install " ) . arg ( BlenderDir ) ) ;
if ( Action = = PR_INSTALL )
{
mProcess - > start ( BlenderExe , Arguments ) ;
}
else
{
# ifdef Q_OS_WIN
mProcess - > start ( ShellProgram , QStringList ( ) < < " /C " < < Script . fileName ( ) ) ;
# else
mProcess - > start ( ShellProgram , QStringList ( ) < < Script . fileName ( ) ) ;
# endif
}
if ( ! mProcess - > waitForStarted ( ) )
{
2023-07-07 00:51:51 +02:00
Message = tr ( " Cannot start Blender %1 mProcess. \n %2 " ) . arg ( ProcessAction ) . arg ( QString ( mProcess - > readAllStandardError ( ) ) ) ;
2023-06-02 00:20:49 +02:00
delete mProcess ;
mProcess = nullptr ;
return PR_WAIT ;
}
else
{
if ( mProcess - > exitStatus ( ) ! = QProcess : : NormalExit | | mProcess - > exitCode ( ) ! = 0 )
{
2023-07-07 00:51:51 +02:00
Message = tr ( " Failed to execute Blender %1. \n %2 " ) . arg ( ProcessAction ) . arg ( QString ( mProcess - > readAllStandardError ( ) ) ) ;
2023-06-02 00:20:49 +02:00
return PR_FAIL ;
}
}
if ( Action = = PR_TEST )
{
while ( mProcess & & mProcess - > state ( ) ! = QProcess : : NotRunning )
{
QTime Waiting = QTime : : currentTime ( ) . addMSecs ( 500 ) ;
while ( QTime : : currentTime ( ) < Waiting )
QCoreApplication : : processEvents ( QEventLoop : : AllEvents , 100 ) ;
}
connect ( & mUpdateTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( Update ( ) ) ) ;
2023-07-07 00:51:51 +02:00
const QString StdOut = QString ( mProcess - > readAllStandardOutput ( ) ) ;
2023-06-02 00:20:49 +02:00
if ( ! StdOut . contains ( BlenderTestString ) )
{
Message = tr ( " A simple check to test if the selected file is Blender failed. "
" Please create an %1 GitHub ticket if you are sure the file is Blender 2.8 or newer. "
" The ticket should contain the full path to the Blender executable. " ) . arg ( LC_PRODUCTNAME_STR ) ;
return PR_FAIL ;
}
else
{
QStringList Items = StdOut . split ( ' \n ' , SkipEmptyParts ) . last ( ) . split ( " " ) ;
if ( Items . count ( ) > 6 & & Items . at ( 0 ) = = QLatin1String ( " Blender " ) )
{
Items . takeLast ( ) ;
mBlenderVersion . clear ( ) ;
for ( int LblIdx = 1 ; LblIdx < Items . size ( ) ; LblIdx + + )
mBlenderVersion . append ( Items . at ( LblIdx ) + " " ) ;
mBlenderVersionFound = ! mBlenderVersion . isEmpty ( ) ;
if ( mBlenderVersionFound )
{
mBlenderVersion = mBlenderVersion . trimmed ( ) . prepend ( " v " ) . append ( " ) " ) ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
// set default LDraw import module if not configured
if ( ! mImportActBox - > isChecked ( ) & & ! mImportMMActBox - > isChecked ( ) )
mImportActBox - > setChecked ( true ) ;
Message = tr ( " Blender %1 mProcess completed. Version: %2 validated. " ) . arg ( ProcessAction ) . arg ( mBlenderVersion ) ;
}
}
}
}
return PR_OK ;
} ;
connect ( & mUpdateTimer , SIGNAL ( timeout ( ) ) , this , SLOT ( Update ( ) ) ) ;
mUpdateTimer . start ( 500 ) ;
if ( ! ModuleChange )
{
mProgressBar = new QProgressBar ( mContent ) ;
mProgressBar - > setMaximum ( 0 ) ;
mProgressBar - > setMinimum ( 0 ) ;
mProgressBar - > setValue ( 1 ) ;
TestBlender | = sender ( ) = = mPathLineEditList [ PATH_BLENDER ] ;
if ( TestBlender )
{
mExeGridLayout - > replaceWidget ( mBlenderVersionEdit , mProgressBar ) ;
mProgressBar - > show ( ) ;
Arguments < < QString ( " --factory-startup " ) ;
Arguments < < QString ( " -b " ) ;
Arguments < < QString ( " --python-expr " ) ;
Arguments < < QString ( " \" import sys;print('%1');sys.stdout.flush();sys.exit() \" " ) . arg ( BlenderTestString ) ;
bool Error = false ;
QString ScriptName , ScriptCommand ;
# ifdef Q_OS_WIN
ScriptName = QLatin1String ( " blender_test.bat " ) ;
# else
ScriptName = QLatin1String ( " blender_test.sh " ) ;
# endif
ScriptCommand = QString ( " %1 %2 " ) . arg ( BlenderExe ) . arg ( Arguments . join ( " " ) ) ;
Script . setFileName ( QString ( " %1/%2 " ) . arg ( QDir : : tempPath ( ) ) . arg ( ScriptName ) ) ;
if ( Script . open ( QIODevice : : WriteOnly | QIODevice : : Text ) )
{
QTextStream Stream ( & Script ) ;
# ifdef Q_OS_WIN
Stream < < QLatin1String ( " @ECHO OFF& SETLOCAL " ) < < LineEnding ;
# else
Stream < < QLatin1String ( " #!/bin/bash " ) < < LineEnding ;
# endif
Stream < < ScriptCommand < < LineEnding ;
Script . close ( ) ;
}
else
{
2023-07-07 00:51:51 +02:00
Message = tr ( " Cannot write Blender render script file [%1] %2. " ) . arg ( Script . fileName ( ) ) . arg ( Script . errorString ( ) ) ;
2023-06-02 00:20:49 +02:00
Error = true ;
}
if ( Error )
{
StatusUpdate ( false ) ;
return ;
}
QThread : : sleep ( 1 ) ;
# ifdef Q_OS_WIN
ShellProgram = QLatin1String ( LC_WINDOWS_SHELL ) ;
# else
ShellProgram = QLatin1String ( LC_UNIX_SHELL ) ;
# endif
Result = ProcessCommand ( PR_TEST ) ;
bool TestOk = Result ! = PR_FAIL ;
2023-07-07 00:51:51 +02:00
const QString statusLabel = TestOk ? " " : tr ( " Blender test failed. " ) ;
2023-06-02 00:20:49 +02:00
StatusUpdate ( false , TestOk , statusLabel ) ;
if ( TestOk )
{
lcSetProfileString ( LC_PROFILE_BLENDER_VERSION , mBlenderVersion ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_PATH , BlenderExe ) ;
}
else
{
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " %1 Blender LDraw Addon " ) . arg ( LC_PRODUCTNAME_STR ) ;
const QString & Header = tr ( " Blender test failed. " ) ;
2023-06-02 00:20:49 +02:00
ShowMessage ( Header , Title , Message ) ;
return ;
}
} // Test Blender
if ( ! mBlenderVersion . isEmpty ( ) & & ! mImportMMActBox - > isChecked ( ) & & ! mImportActBox - > isChecked ( ) )
{
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " %1 Blender LDraw Addon Modules " ) . arg ( LC_PRODUCTNAME_STR ) ;
const QString & Header = tr ( " No import module enabled. If you continue, the default import module (Import TN) will be used.<br>If you select No, all addon modules will be disabled. " ) ;
const QString & Body = tr ( " Continue with the default import module ? " ) ;
2023-06-02 00:20:49 +02:00
int Exec = ShowMessage ( Header , Title , Body , QString ( ) , MBB_YES_NO , QMessageBox : : NoIcon ) ;
if ( Exec ! = QMessageBox : : Yes )
{
mRenderActBox - > setChecked ( false ) ;
if ( Exec = = QMessageBox : : Cancel )
return ;
}
mImportActBox - > setChecked ( true ) ;
}
if ( TestBlender )
{
2023-07-07 00:51:51 +02:00
const QString preferredImportModule = mImportActBox - > isChecked ( ) ? QString ( " TN " ) : mImportMMActBox - > isChecked ( ) ? QString ( " MM " ) : QString ( ) ; // disable all import modules
2023-06-02 00:20:49 +02:00
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , preferredImportModule ) ;
}
else
mBlenderVersionEdit - > setVisible ( AddonUpdate ) ;
if ( mProgressBar )
{
mProgressBar - > setMaximum ( 0 ) ;
mProgressBar - > setMinimum ( 0 ) ;
mProgressBar - > setValue ( 1 ) ;
mAddonGridLayout - > replaceWidget ( mAddonVersionEdit , mProgressBar ) ;
mProgressBar - > show ( ) ;
}
if ( ! ExtractBlenderAddon ( BlenderDir ) )
{
if ( AddonUpdate )
{
mConfigured = true ;
mBlenderVersionLabel - > setText ( tr ( " Blender " ) ) ;
mBlenderVersionLabel - > setStyleSheet ( QString ( " QLabel { color : %1; } " ) . arg ( QApplication : : palette ( ) . text ( ) . color ( ) . name ( ) ) ) ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
mBlenderVersionEdit - > setToolTip ( tr ( " Display the Blender and %1 Render addon version " ) . arg ( LC_PRODUCTNAME_STR ) ) ;
mBlenderVersionEdit - > setVisible ( mConfigured ) ;
if ( ! mAddonVersion . isEmpty ( ) )
{
mModulesBox - > setEnabled ( true ) ;
mAddonVersionEdit - > setText ( mAddonVersion ) ;
}
mAddonUpdateButton - > setEnabled ( mConfigured ) ;
if ( mProgressBar )
{
mExeGridLayout - > replaceWidget ( mProgressBar , mAddonVersionEdit ) ;
mProgressBar - > close ( ) ;
}
}
return ;
}
if ( ! QFileInfo ( BlenderInstallFile ) . exists ( ) )
{
ShowMessage ( tr ( " Could not find addon install file: %1 " ) . arg ( BlenderInstallFile ) ) ;
StatusUpdate ( true , true , tr ( " Addon file not found. " ) ) ;
return ;
}
StatusUpdate ( true , false , tr ( " Install addon... " ) ) ;
QDir ConfigDir ( BlenderConfigDir ) ;
if ( ! QDir ( ConfigDir ) . exists ( ) )
ConfigDir . mkpath ( " . " ) ;
}
SaveSettings ( ) ;
Arguments . clear ( ) ;
Arguments < < QString ( " --background " ) ;
Arguments < < QString ( " --python " ) ;
Arguments < < BlenderInstallFile ;
Arguments < < " -- " ;
if ( ! mRenderActBox - > isChecked ( ) & & ! mImportActBox - > isChecked ( ) & & ! mImportMMActBox - > isChecked ( ) )
Arguments < < QString ( " --disable_ldraw_addons " ) ;
else if ( ! mImportActBox - > isChecked ( ) )
Arguments < < QString ( " --disable_ldraw_import " ) ;
else if ( ! mImportMMActBox - > isChecked ( ) )
Arguments < < QString ( " --disable_ldraw_import_mm " ) ;
else if ( ! mRenderActBox - > isChecked ( ) )
Arguments < < QString ( " --disable_ldraw_render " ) ;
Arguments < < QString ( " --leocad " ) ;
Message = tr ( " Blender Addon Install Arguments: %1 %2 " ) . arg ( BlenderExe ) . arg ( Arguments . join ( " " ) ) ;
if ( ! TestBlender )
mBlenderVersionFound = false ;
if ( QDir ( BlenderAddonDir ) . entryInfoList ( QDir : : Dirs | QDir : : NoSymLinks ) . count ( ) > 0 )
{
QJsonArray JsonArray ;
QStringList AddonDirs = QDir ( BlenderAddonDir ) . entryList ( QDir : : NoDotAndDotDot | QDir : : Dirs , QDir : : SortByMask ) ;
2023-07-07 00:51:51 +02:00
for ( const QString & Addon : AddonDirs )
2023-06-02 00:20:49 +02:00
{
QDir Dir ( QString ( " %1/%2 " ) . arg ( BlenderAddonDir ) . arg ( Addon ) ) ;
Dir . setFilter ( QDir : : Files | QDir : : NoDotAndDotDot | QDir : : NoSymLinks ) ;
QFileInfoList List = Dir . entryInfoList ( ) ;
for ( int LblIdx = 0 ; LblIdx < List . size ( ) ; LblIdx + + )
{
if ( List . at ( LblIdx ) . fileName ( ) = = QLatin1String ( " __init__.py " ) )
{
QFile File ( QFileInfo ( List . at ( LblIdx ) ) . absoluteFilePath ( ) ) ;
if ( ! File . open ( QFile : : ReadOnly | QFile : : Text ) )
{
ShowMessage ( tr ( " Cannot read addon file %1<br>%2 " ) . arg ( List . at ( LblIdx ) . fileName ( ) ) . arg ( File . errorString ( ) ) ) ;
break ;
}
else
{
bool FoundModule = false ;
QTextStream In ( & File ) ;
while ( ! In . atEnd ( ) )
{
if ( QString ( In . readLine ( 0 ) ) . startsWith ( " bl_info " ) )
{
FoundModule = true ;
break ;
}
}
File . close ( ) ;
if ( FoundModule )
{
QJsonObject JsonItemObj ;
JsonItemObj [ " load_dir " ] = QDir : : toNativeSeparators ( Dir . absolutePath ( ) ) ;
JsonItemObj [ " module_name " ] = Dir . dirName ( ) ;
JsonArray . append ( JsonItemObj ) ;
}
}
}
}
}
QJsonDocument JsonDoc ;
JsonDoc . setArray ( JsonArray ) ;
AddonPathsAndModuleNames = JsonDoc . toJson ( QJsonDocument : : Compact ) ;
}
Result = ProcessCommand ( PR_INSTALL ) ;
if ( Result ! = PR_OK )
StatusUpdate ( true , true , tr ( " Addon install failed. " ) ) ;
}
else
ShowMessage ( tr ( " Blender executable not found at [%1] " ) . arg ( BlenderExe ) , tr ( " Addon install failed. " ) ) ;
}
bool lcBlenderPreferences : : ExtractBlenderAddon ( const QString & BlenderDir )
{
bool Proceed = true ;
QDir Dir ( BlenderDir ) ;
if ( ! Dir . exists ( ) )
Dir . mkdir ( BlenderDir ) ;
if ( GetBlenderAddon ( BlenderDir ) )
{
gAddonPreferences - > StatusUpdate ( true , false , tr ( " Extract addon... " ) ) ;
2023-07-07 00:51:51 +02:00
const QString BlenderAddonFile = QDir : : toNativeSeparators ( QString ( " %1/%2 " ) . arg ( BlenderDir ) . arg ( LC_BLENDER_ADDON_FILE ) ) ;
2023-05-26 16:17:59 +02:00
QString Result ;
bool Success = gAddonPreferences - > ExtractAddon ( BlenderAddonFile , Result ) ;
if ( ! Success )
2023-06-02 00:20:49 +02:00
{
2023-07-07 00:51:51 +02:00
QString Message = tr ( " Failed to extract %1 to %2 " ) . arg ( LC_BLENDER_ADDON_FILE ) . arg ( BlenderDir ) ;
2023-05-26 16:17:59 +02:00
if ( Result . size ( ) )
Message . append ( " " + Result ) ;
ShowMessage ( Message , tr ( " Extract addon " ) ) ;
Proceed = false ;
2023-06-02 00:20:49 +02:00
}
}
if ( ! Proceed )
gAddonPreferences - > StatusUpdate ( true , true , tr ( " Extract addon failed. " ) ) ;
return Proceed ;
}
bool lcBlenderPreferences : : GetBlenderAddon ( const QString & BlenderDir )
{
enum AddonEnc
{
ADDON_FAIL = - 1 ,
ADDON_NOT_FOUND ,
ADDON_DOWNLOAD = ADDON_NOT_FOUND ,
ADDON_ARCHIVE ,
ADDON_EXTRACTED ,
ADDON_RELOAD ,
ADDON_CANCEL
} ;
2023-07-07 00:51:51 +02:00
const QString BlenderAddonDir = QDir : : toNativeSeparators ( QString ( " %1/addons " ) . arg ( BlenderDir ) ) ;
const QString BlenderAddonFile = QDir : : toNativeSeparators ( QString ( " %1/%2 " ) . arg ( BlenderDir ) . arg ( LC_BLENDER_ADDON_FILE ) ) ;
const QString AddonVersionFile = QDir : : toNativeSeparators ( QString ( " %1/%2/__version__.py " ) . arg ( BlenderAddonDir ) . arg ( LC_BLENDER_ADDON_FOLDER_STR ) ) ;
2023-06-02 00:20:49 +02:00
bool ExtractedAddon = QFileInfo ( AddonVersionFile ) . isReadable ( ) ;
bool BlenderAddonExists = ExtractedAddon | | QFileInfo ( BlenderAddonFile ) . isReadable ( ) ;
QString AddonStatus = tr ( " Installing Blender addon... " ) ;
AddonEnc AddonAction = ADDON_DOWNLOAD ;
QString LocalVersion , OnlineVersion ;
using namespace std ;
auto VersionStringCompare = [ ] ( string V1 , string V2 )
{ // Returns 1 if V2 is smaller, -1 if V1 is smaller, 0 if equal
int Vnum1 = 0 , Vnum2 = 0 ;
for ( quint32 i = 0 , j = 0 ; ( i < V1 . length ( ) | | j < V2 . length ( ) ) ; )
{
while ( i < V1 . length ( ) & & V1 [ i ] ! = ' . ' )
{
Vnum1 = Vnum1 * 10 + ( V1 [ i ] - ' 0 ' ) ;
i + + ;
}
while ( j < V2 . length ( ) & & V2 [ j ] ! = ' . ' )
{
Vnum2 = Vnum2 * 10 + ( V2 [ j ] - ' 0 ' ) ;
j + + ;
}
if ( Vnum1 > Vnum2 )
return 1 ;
if ( Vnum2 > Vnum1 )
return - 1 ;
Vnum1 = Vnum2 = 0 ;
i + + ;
j + + ;
}
return 0 ;
} ;
auto GetBlenderAddonVersionMatch = [ & ] ( )
{
2023-05-26 16:17:16 +02:00
lcHttpManager * HttpManager = new lcHttpManager ( gAddonPreferences ) ;
connect ( HttpManager , SIGNAL ( DownloadFinished ( lcHttpReply * ) ) , gAddonPreferences , SLOT ( DownloadFinished ( lcHttpReply * ) ) ) ;
gAddonPreferences - > mHttpReply = HttpManager - > DownloadFile ( QLatin1String ( LC_BLENDER_ADDON_LATEST_URL ) ) ;
while ( gAddonPreferences - > mHttpReply )
QApplication : : processEvents ( ) ;
if ( ! gAddonPreferences - > mData . isEmpty ( ) )
{
QJsonDocument Json = QJsonDocument : : fromJson ( gAddonPreferences - > mData ) ;
OnlineVersion = Json . object ( ) [ " tag_name " ] . toString ( ) ;
gAddonPreferences - > mData . clear ( ) ;
}
else
{
ShowMessage ( tr ( " Check latest addon version failed. " ) , tr ( " Latest Addon " ) , QString ( ) , QString ( ) , MBB_OK , QMessageBox : : Warning ) ;
return true ; // Reload existing archive
}
2023-06-02 00:20:49 +02:00
QByteArray Ba ;
if ( ! ExtractedAddon )
{
2023-05-26 16:17:59 +02:00
const char * VersionFile = " addons/ " LC_BLENDER_ADDON_FOLDER_STR " /__version__.py " ;
lcZipFile ZipFile ;
if ( ! ZipFile . OpenRead ( BlenderAddonFile ) )
2023-06-02 00:20:49 +02:00
{
2023-05-26 16:17:59 +02:00
ShowMessage ( tr ( " Cannot open addon archive file: %1. " ) . arg ( BlenderAddonFile ) ) ;
return false ;
2023-06-02 00:20:49 +02:00
}
2023-05-26 16:17:59 +02:00
lcMemFile File ;
if ( ! ZipFile . ExtractFile ( VersionFile , File ) )
2023-06-02 00:20:49 +02:00
{
2023-05-26 16:17:59 +02:00
ShowMessage ( tr ( " Cannot extract addon archive version file: %1. " ) . arg ( VersionFile ) ) ;
return false ;
}
2023-06-19 03:04:08 +02:00
Ba = QByteArray : : fromRawData ( ( const char * ) File . mBuffer , ( int ) File . GetLength ( ) ) ;
2023-05-26 16:17:59 +02:00
if ( Ba . isEmpty ( ) )
{
ShowMessage ( tr ( " Cannot read addon archive version file: %1. " ) . arg ( VersionFile ) ) ;
2023-06-02 00:20:49 +02:00
return false ; // Download new archive
}
}
else
{
QFile File ( AddonVersionFile ) ;
if ( ! File . open ( QIODevice : : ReadOnly ) )
{
2023-07-07 00:51:51 +02:00
ShowMessage ( tr ( " Cannot read addon version file: [%1]<br>%2. " ) . arg ( AddonVersionFile ) . arg ( File . errorString ( ) ) ) ;
2023-06-02 00:20:49 +02:00
return false ; // Download new archive
}
Ba = File . readAll ( ) ;
File . close ( ) ;
}
QTextStream Content ( Ba . data ( ) ) ;
while ( ! Content . atEnd ( ) )
{
QString Token ;
Content > > Token ;
if ( Token = = QLatin1String ( " version " ) )
{
Content > > Token ;
LocalVersion = Content . readAll ( ) . trimmed ( ) . replace ( " ( " , " v " ) . replace ( " , " , " . " ) . replace ( " " , " " ) . replace ( " ) " , " " ) ;
}
}
if ( ! LocalVersion . isEmpty ( ) & & ! OnlineVersion . isEmpty ( ) )
{
2023-05-26 16:17:16 +02:00
// localVersion is smaller than onlineVersion so prompt to download new archive
2023-06-02 00:20:49 +02:00
if ( VersionStringCompare ( LocalVersion . toStdString ( ) , OnlineVersion . toStdString ( ) ) < 0 )
2023-05-26 16:17:16 +02:00
return false ; // Download new archive
2023-06-02 00:20:49 +02:00
}
return true ; // Reload existing archive
} ;
if ( BlenderAddonExists )
{
if ( GetBlenderAddonVersionMatch ( ) )
{
AddonAction = ADDON_RELOAD ;
}
else if ( gMainWindow )
{
2023-07-30 11:43:13 +02:00
if ( lcGetProfileInt ( LC_PROFILE_BLENDER_ADDON_VERSION_CHECK ) )
2023-06-02 00:20:49 +02:00
{
2023-07-30 11:43:13 +02:00
if ( LocalVersion . isEmpty ( ) )
LocalVersion = gAddonPreferences - > mAddonVersion ;
const QString & Title = tr ( " %1 Blender LDraw Addon " ) . arg ( LC_PRODUCTNAME_STR ) ;
const QString & Header = tr ( " Detected %1 Blender LDraw addon %2. A newer version %3 exists. " ) . arg ( LC_PRODUCTNAME_STR ) . arg ( LocalVersion ) . arg ( OnlineVersion ) ;
const QString & Body = tr ( " Do you want to download version %1 ? " ) . arg ( OnlineVersion ) ;
int Exec = ShowMessage ( Header , Title , Body , QString ( ) , MBB_YES , QMessageBox : : NoIcon ) ;
if ( Exec = = QMessageBox : : Cancel )
{
AddonStatus = tr ( " Blender addon setup cancelled " ) ;
AddonAction = ADDON_CANCEL ;
}
else if ( Exec = = QMessageBox : : No )
{
AddonAction = ADDON_RELOAD ;
}
2023-06-02 00:20:49 +02:00
}
2023-07-30 11:43:13 +02:00
else
2023-06-02 00:20:49 +02:00
{
AddonAction = ADDON_RELOAD ;
}
}
if ( AddonAction = = ADDON_DOWNLOAD )
AddonStatus = tr ( " Download addon... " ) ;
gAddonPreferences - > StatusUpdate ( true , false , AddonStatus ) ;
if ( AddonAction = = ADDON_CANCEL )
{
gAddonPreferences - > mDialogCancelled = true ;
return false ;
}
}
if ( QFileInfo ( BlenderAddonDir ) . exists ( ) )
{
bool Result = true ;
QDir Dir ( BlenderAddonDir ) ;
for ( QFileInfo const & FileInfo : Dir . entryInfoList ( QDir : : Dirs | QDir : : NoDotAndDotDot | QDir : : NoSymLinks , QDir : : DirsFirst ) )
{
if ( FileInfo . isDir ( ) )
Result & = QDir ( FileInfo . absoluteFilePath ( ) ) . removeRecursively ( ) ;
else
Result & = QFile : : remove ( FileInfo . absoluteFilePath ( ) ) ;
}
Result & = Dir . rmdir ( BlenderAddonDir ) ;
if ( ! Result )
2023-07-07 00:51:51 +02:00
ShowMessage ( tr ( " Failed to remove Blender addon: %1 " ) . arg ( BlenderAddonDir ) , tr ( " Remove Existing Addon " ) , QString ( ) , QString ( ) , MBB_OK , QMessageBox : : Warning ) ;
2023-06-02 00:20:49 +02:00
}
if ( AddonAction = = ADDON_DOWNLOAD )
{
BlenderAddonExists = false ;
2023-05-26 16:17:16 +02:00
lcHttpManager * HttpManager = new lcHttpManager ( gAddonPreferences ) ;
connect ( HttpManager , SIGNAL ( DownloadFinished ( lcHttpReply * ) ) , gAddonPreferences , SLOT ( DownloadFinished ( lcHttpReply * ) ) ) ;
gAddonPreferences - > mHttpReply = HttpManager - > DownloadFile ( QLatin1String ( LC_BLENDER_ADDON_URL ) ) ;
while ( gAddonPreferences - > mHttpReply )
QApplication : : processEvents ( ) ;
if ( ! gAddonPreferences - > mData . isEmpty ( ) )
2023-06-02 00:20:49 +02:00
{
if ( QFileInfo ( BlenderAddonFile ) . exists ( ) )
{
QDir Dir ( BlenderDir ) ;
if ( ! Dir . remove ( BlenderAddonFile ) )
ShowMessage ( tr ( " Failed to remove Blender addon archive:<br>%1 " ) . arg ( BlenderAddonFile ) ) ;
}
QFile File ( BlenderAddonFile ) ;
if ( File . open ( QIODevice : : WriteOnly ) )
{
2023-05-26 16:17:16 +02:00
File . write ( gAddonPreferences - > mData ) ;
2023-06-02 00:20:49 +02:00
File . close ( ) ;
BlenderAddonExists = true ;
2023-05-26 16:17:16 +02:00
gAddonPreferences - > mData . clear ( ) ;
2023-06-02 00:20:49 +02:00
}
else
2023-07-07 00:51:51 +02:00
ShowMessage ( tr ( " Failed to open Blender addon file:<br>%1:<br>%2 " ) . arg ( BlenderAddonFile ) . arg ( File . errorString ( ) ) ) ;
2023-06-02 00:20:49 +02:00
}
else
ShowMessage ( tr ( " Failed to download Blender addon archive:<br>%1 " ) . arg ( BlenderAddonFile ) ) ;
if ( ! BlenderAddonExists )
{
AddonStatus = tr ( " Download addon failed. " ) ;
gAddonPreferences - > StatusUpdate ( true , true , AddonStatus ) ;
}
}
else if ( ! BlenderAddonExists )
ShowMessage ( tr ( " Blender addon archive %1 was not found " ) . arg ( BlenderAddonFile ) ) ;
return BlenderAddonExists ;
}
void lcBlenderPreferences : : StatusUpdate ( bool Addon , bool Error , const QString & Message )
{
QString Label , Colour ;
2023-07-07 00:51:51 +02:00
const QString Which = Addon ? tr ( " Blender addon " ) : tr ( " Blender " ) ;
2023-06-02 00:20:49 +02:00
if ( mProgressBar )
{
if ( Addon )
{
mAddonGridLayout - > replaceWidget ( mProgressBar , mAddonVersionEdit ) ;
}
else
{
mExeGridLayout - > replaceWidget ( mProgressBar , mBlenderVersionEdit ) ;
mProgressBar - > hide ( ) ;
}
}
if ( Error )
{
if ( ! Addon )
mPathLineEditList [ PATH_BLENDER ] - > text ( ) = QString ( ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , QString ( ) ) ;
const lcPreferences & Preferences = lcGetPreferences ( ) ;
Label = ! Message . isEmpty ( ) ? Message : tr ( " %1 not configured " ) . arg ( Which ) ;
Colour = Message . startsWith ( " Error: " , Qt : : CaseInsensitive )
? QLatin1String ( " red " )
: Preferences . mColorTheme = = lcColorTheme : : Dark
? QLatin1String ( LC_THEME_DARK_DECORATE_QUOTED_TEXT )
: QLatin1String ( " blue " ) ;
mDialogCancelled = true ;
}
else
{
Label = ! Message . isEmpty ( ) ? Message : tr ( " %1 setup... " ) . arg ( Which ) ;
Colour = QApplication : : palette ( ) . text ( ) . color ( ) . name ( ) ;
}
if ( Addon )
{
mAddonVersionLabel - > setStyleSheet ( QString ( " QLabel { color : %1; } " ) . arg ( Colour ) ) ;
mAddonVersionLabel - > setText ( Label ) ;
mAddonVersionEdit - > setVisible ( ! mAddonVersion . isEmpty ( ) ) ;
}
else
{
mBlenderVersionLabel - > setStyleSheet ( QString ( " QLabel { color : %1; } " ) . arg ( Colour ) ) ;
mBlenderVersionLabel - > setText ( Label ) ;
mBlenderVersionEdit - > setVisible ( ! mBlenderVersion . isEmpty ( ) ) ;
}
}
void lcBlenderPreferences : : ShowResult ( )
{
QString Message ;
bool Error ;
const QString StdErrLog = ReadStdErr ( Error ) ;
if ( mProgressBar )
mProgressBar - > close ( ) ;
WriteStdOut ( ) ;
if ( mProcess - > exitStatus ( ) ! = QProcess : : NormalExit | | mProcess - > exitCode ( ) ! = 0 | | Error )
{
2023-07-07 00:51:51 +02:00
const QString BlenderDir = QString ( " %1/Blender " ) . arg ( mDataDir ) ;
2023-06-02 00:20:49 +02:00
Message = tr ( " Addon install failed. See %1/stderr-blender-addon-install for details. " ) . arg ( BlenderDir ) ;
StatusUpdate ( true , true , tr ( " %1: Addon install failed. " ) . arg ( " Error " ) ) ;
mConfigured = false ;
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " %1 Blender Addon Install " ) . arg ( LC_PRODUCTNAME_STR ) ;
const QString & Header = " <b> " + tr ( " Addon install failed. " ) + " </b> " ;
const QString & Body = tr ( " LDraw addon install encountered one or more errors. See Show Details... " ) ;
2023-06-19 04:06:44 +02:00
ShowMessage ( Header , Title , Body , StdErrLog , MBB_OK , QMessageBox : : Warning ) ;
2023-06-02 00:20:49 +02:00
}
else
{
2023-07-07 00:51:51 +02:00
const QString TextColour = QString ( " QLabel { color : %1; } " ) . arg ( QApplication : : palette ( ) . text ( ) . color ( ) . name ( ) ) ;
2023-06-02 00:20:49 +02:00
mAddonGridLayout - > replaceWidget ( mProgressBar , mAddonVersionEdit ) ;
mConfigured = true ;
mBlenderVersionLabel - > setText ( tr ( " Blender " ) ) ;
mBlenderVersionLabel - > setStyleSheet ( TextColour ) ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
mBlenderVersionEdit - > setToolTip ( tr ( " Display the Blender and %1 Render addon version " ) . arg ( LC_PRODUCTNAME_STR ) ) ;
mBlenderVersionEdit - > setVisible ( mConfigured ) ;
mPathsBox - > setEnabled ( mConfigured ) ;
mSettingsBox - > setEnabled ( mConfigured ) ;
if ( ! mAddonVersion . isEmpty ( ) )
{
mAddonVersionLabel - > setText ( tr ( " Blender Addon " ) ) ;
mAddonVersionLabel - > setStyleSheet ( TextColour ) ;
mAddonVersionEdit - > setText ( mAddonVersion ) ;
mAddonVersionEdit - > setVisible ( true ) ;
mModulesBox - > setEnabled ( true ) ;
mAddonUpdateButton - > setEnabled ( true ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_VERSION , mBlenderVersion ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_ADDON_VERSION , mAddonVersion ) ;
SetModelSize ( true ) ;
SaveSettings ( ) ;
mDialogCancelled = false ;
}
Message = tr ( " Blender version %1 " ) . arg ( mBlenderVersion ) ;
}
delete mProcess ;
mProcess = nullptr ;
if ( Error )
ShowMessage ( Message ) ;
}
void lcBlenderPreferences : : SettingChanged ( const QString & Value )
{
bool Change = false ;
QLineEdit * LineEdit = qobject_cast < QLineEdit * > ( sender ( ) ) ;
if ( LineEdit )
{
int LblIdx = LineEdit - > property ( " ControlID " ) . toInt ( ) ;
if ( mImportMMActBox - > isChecked ( ) )
{
Change = mBlenderSettingsMM [ LblIdx ] . value ! = Value ;
}
else
{
Change = mBlenderSettings [ LblIdx ] . value ! = Value ;
}
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
}
void lcBlenderPreferences : : SettingChanged ( int Index )
{
int LblIdx = - 1 ;
bool Change = false ;
QString Item ;
if ( Index > - 1 )
{
QComboBox * ComboBox = qobject_cast < QComboBox * > ( sender ( ) ) ;
if ( ComboBox )
{
LblIdx = ComboBox - > property ( " ControlID " ) . toInt ( ) ;
Item = ComboBox - > itemData ( Index ) . toString ( ) ;
}
}
else
{
QCheckBox * CheckBox = qobject_cast < QCheckBox * > ( sender ( ) ) ;
if ( CheckBox )
{
LblIdx = CheckBox - > property ( " ControlID " ) . toInt ( ) ;
Item = QString : : number ( CheckBox - > isChecked ( ) ) ;
}
}
if ( LblIdx > - 1 )
{
if ( mImportMMActBox - > isChecked ( ) )
{
Change = mBlenderSettingsMM [ LblIdx ] . value ! = Item ;
}
else
{
Change = mBlenderSettings [ LblIdx ] . value ! = Item ;
}
}
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
void lcBlenderPreferences : : PathChanged ( )
{
QLineEdit * LineEdit = qobject_cast < QLineEdit * > ( sender ( ) ) ;
if ( LineEdit )
{
bool Change = false ;
const int LblIdx = LineEdit - > property ( " ControlID " ) . toInt ( ) ;
const QString & Path = QDir : : toNativeSeparators ( LineEdit - > text ( ) ) . toLower ( ) ;
if ( LblIdx ! = PATH_BLENDER )
{
Change = QDir : : toNativeSeparators ( mBlenderPaths [ LblIdx ] . value ) . toLower ( ) ! = Path ;
}
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
}
void lcBlenderPreferences : : GetStandardOutput ( )
{
2023-07-07 00:51:51 +02:00
const QString LogFile = QString ( " %1/Blender/stdout-blender-addon-install " ) . arg ( mDataDir ) ;
2023-06-02 00:20:49 +02:00
QFileInfo FileInfo ( LogFile ) ;
if ( ! FileInfo . exists ( ) )
{
ShowMessage ( tr ( " Blender addon standard output file not found: %1. " ) . arg ( FileInfo . absoluteFilePath ( ) ) ) ;
return ;
}
if ( LogFile . isEmpty ( ) )
return ;
QDesktopServices : : openUrl ( QUrl ( " file:/// " + LogFile , QUrl : : TolerantMode ) ) ;
}
void lcBlenderPreferences : : ReadStdOut ( const QString & StdOutput , QString & Errors )
{
2024-04-28 02:19:34 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QRegularExpression RxInfo ( " ^INFO: " ) ;
QRegularExpression RxData ( " ^DATA: " ) ;
QRegularExpression RxError ( " ^(?: \\ w) * ERROR : " , QRegularExpression::CaseInsensitiveOption) ;
QRegularExpression RxWarning ( " ^(?: \\ w) * WARNING : " , QRegularExpression::CaseInsensitiveOption) ;
QRegularExpression RxAddonVersion ( " ^ADDON VERSION: " , QRegularExpression : : CaseInsensitiveOption ) ;
QStringList StdOutLines = StdOutput . split ( QRegularExpression ( " \n | \r \n | \r " ) ) ;
# else
2023-06-02 00:20:49 +02:00
QRegExp RxInfo ( " ^INFO: " ) ;
QRegExp RxData ( " ^DATA: " ) ;
QRegExp RxError ( " ^(?: \\ w) * ERROR : " , Qt::CaseInsensitive) ;
QRegExp RxWarning ( " ^(?: \\ w) * WARNING : " , Qt::CaseInsensitive) ;
QRegExp RxAddonVersion ( " ^ADDON VERSION: " , Qt : : CaseInsensitive ) ;
2024-04-28 02:19:34 +02:00
QStringList StdOutLines = StdOutput . split ( QRegExp ( " \n | \r \n | \r " ) ) ;
# endif
2023-06-02 00:20:49 +02:00
bool ErrorEncountered = false ;
QStringList Items , ErrorList ;
2023-07-07 00:51:51 +02:00
const QString SaveAddonVersion = mAddonVersion ;
const QString SaveVersion = mBlenderVersion ;
2023-06-02 00:20:49 +02:00
int EditListItems = mPathLineEditList . size ( ) ;
2023-07-07 00:51:51 +02:00
for ( const QString & StdOutLine : StdOutLines )
2023-06-02 00:20:49 +02:00
{
if ( StdOutLine . isEmpty ( ) )
continue ;
if ( ! mBlenderVersionFound )
{
Items = StdOutLine . split ( " " ) ;
if ( Items . count ( ) > 6 & & Items . at ( 0 ) = = QLatin1String ( " Blender " ) )
{
Items . takeLast ( ) ;
mBlenderVersion . clear ( ) ;
for ( int LblIdx = 1 ; LblIdx < Items . size ( ) ; LblIdx + + )
mBlenderVersion . append ( Items . at ( LblIdx ) + " " ) ;
mBlenderVersionFound = ! mBlenderVersion . isEmpty ( ) ;
if ( mBlenderVersionFound )
{
mBlenderVersion = mBlenderVersion . trimmed ( ) . prepend ( " v " ) . append ( " ) " ) ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
if ( ! mImportActBox - > isChecked ( ) & & ! mImportMMActBox - > isChecked ( ) )
mImportActBox - > setChecked ( true ) ;
}
}
}
if ( StdOutLine . contains ( RxInfo ) )
{
Items = StdOutLine . split ( " : " ) ;
}
else if ( StdOutLine . contains ( RxData ) )
{
Items = StdOutLine . split ( " : " ) ;
if ( Items . at ( 1 ) = = " ENVIRONMENT_FILE " )
{
mBlenderPaths [ PATH_ENVIRONMENT ] . value = Items . at ( 2 ) ;
if ( EditListItems > PATH_ENVIRONMENT )
mPathLineEditList [ PATH_ENVIRONMENT ] - > setText ( Items . at ( 2 ) ) ;
}
else if ( Items . at ( 1 ) = = " LSYNTH_DIRECTORY " )
{
mBlenderPaths [ PATH_LSYNTH ] . value = Items . at ( 2 ) ;
if ( EditListItems > PATH_LSYNTH )
mPathLineEditList [ PATH_LSYNTH ] - > setText ( Items . at ( 2 ) ) ;
}
else if ( Items . at ( 1 ) = = " STUDLOGO_DIRECTORY " )
{
mBlenderPaths [ PATH_STUD_LOGO ] . value = Items . at ( 2 ) ;
if ( EditListItems > PATH_STUD_LOGO )
mPathLineEditList [ PATH_STUD_LOGO ] - > setText ( Items . at ( 2 ) ) ;
}
}
else if ( StdOutLine . contains ( RxError ) | | StdOutLine . contains ( RxWarning ) )
{
ErrorList < < StdOutLine . trimmed ( ) + " <br> " ;
if ( ! ErrorEncountered )
ErrorEncountered = StdOutLine . contains ( RxError ) ;
}
else if ( StdOutLine . contains ( RxAddonVersion ) )
{
Items = StdOutLine . split ( " : " ) ;
mAddonVersion = tr ( " v%1 " ) . arg ( Items . at ( 1 ) . trimmed ( ) ) ;
mAddonVersionEdit - > setText ( mAddonVersion ) ;
}
}
if ( ErrorList . size ( ) )
{
if ( ! mBlenderVersionFound )
{
if ( mBlenderVersion ! = SaveVersion )
{
mConfigured = false ;
mBlenderVersion = SaveVersion ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
}
}
if ( mAddonVersion ! = SaveAddonVersion )
{
mConfigured = false ;
mAddonVersion = SaveAddonVersion ;
mAddonVersionEdit - > setText ( mAddonVersion ) ;
}
Errors = ErrorList . join ( " " ) ;
}
}
void lcBlenderPreferences : : ReadStdOut ( )
{
2023-07-07 00:51:51 +02:00
const QString & StdOut = QString ( mProcess - > readAllStandardOutput ( ) ) ;
2023-06-02 00:20:49 +02:00
mStdOutList . append ( StdOut ) ;
2024-04-28 02:19:34 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QRegularExpression RxInfo ( " ^INFO: " ) ;
QRegularExpression RxError ( " (?: \\ w) * ERROR : " , QRegularExpression::CaseInsensitiveOption) ;
QRegularExpression RxWarning ( " (?: \\ w) * WARNING : " , QRegularExpression::CaseInsensitiveOption) ;
# else
2023-06-02 00:20:49 +02:00
QRegExp RxInfo ( " ^INFO: " ) ;
QRegExp RxError ( " (?: \\ w) * ERROR : " , Qt::CaseInsensitive) ;
QRegExp RxWarning ( " (?: \\ w) * WARNING : " , Qt::CaseInsensitive) ;
2024-04-28 02:19:34 +02:00
# endif
2023-06-02 00:20:49 +02:00
bool const Error = StdOut . contains ( RxError ) ;
bool const Warning = StdOut . contains ( RxWarning ) ;
if ( StdOut . contains ( RxInfo ) & & ! Error )
StatusUpdate ( true , false ) ;
QString ErrorsAndWarnings ;
ReadStdOut ( StdOut , ErrorsAndWarnings ) ;
if ( ! ErrorsAndWarnings . isEmpty ( ) )
{
2023-07-07 00:51:51 +02:00
const QString StdOutLog = QDir : : toNativeSeparators ( QString ( " <br>- See %1/Blender/stdout-blender-addon-install " )
2023-06-02 00:20:49 +02:00
. arg ( mDataDir ) ) ;
2023-06-19 04:06:44 +02:00
QMessageBox : : Icon Icon = QMessageBox : : Warning ;
2023-07-07 00:51:51 +02:00
const QString & Items = Error ? tr ( " errors%1 " ) . arg ( Warning ? tr ( " and warnings " ) : " " ) : Warning ? tr ( " warnings " ) : " " ;
2023-06-02 00:20:49 +02:00
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " %1 Blender Addon Install " ) . arg ( LC_PRODUCTNAME_STR ) ;
const QString & Header = " <b> " + tr ( " Addon install standard output. " ) + " </b> " ;
const QString & Body = tr ( " LDraw addon install encountered %1. See Show Details... " ) . arg ( Items ) ;
2023-06-02 00:20:49 +02:00
ShowMessage ( Header , Title , Body , ErrorsAndWarnings . append ( StdOutLog ) , MBB_OK , Icon ) ;
}
}
QString lcBlenderPreferences : : ReadStdErr ( bool & Error ) const
{
auto CleanLine = [ ] ( const QString & Line )
{
return Line . trimmed ( ) + " <br> " ;
} ;
Error = false ;
QStringList ReturnLines ;
2023-07-07 00:51:51 +02:00
const QString BlenderDir = QString ( " %1/Blender " ) . arg ( mDataDir ) ;
2023-06-02 00:20:49 +02:00
QFile File ( QString ( " %1/stderr-blender-addon-install " ) . arg ( BlenderDir ) ) ;
if ( ! File . open ( QFile : : ReadOnly | QFile : : Text ) )
{
2023-07-07 00:51:51 +02:00
const QString Message = tr ( " Failed to open log file: %1: \n %2 " ) . arg ( File . fileName ( ) ) . arg ( File . errorString ( ) ) ;
2023-06-02 00:20:49 +02:00
return Message ;
}
QTextStream In ( & File ) ;
while ( ! In . atEnd ( ) )
{
2023-07-07 00:51:51 +02:00
const QString & Line = In . readLine ( 0 ) ;
2023-06-02 00:20:49 +02:00
ReturnLines < < CleanLine ( Line ) ;
if ( ! Error )
Error = ! Line . isEmpty ( ) ;
}
return ReturnLines . join ( " " ) ;
}
void lcBlenderPreferences : : WriteStdOut ( )
{
2023-07-07 00:51:51 +02:00
const QString BlenderDir = QString ( " %1/Blender " ) . arg ( mDataDir ) ;
2023-06-02 00:20:49 +02:00
QFile File ( QString ( " %1/stdout-blender-addon-install " ) . arg ( BlenderDir ) ) ;
if ( File . open ( QFile : : WriteOnly | QIODevice : : Truncate | QFile : : Text ) )
{
QTextStream Out ( & File ) ;
for ( const QString & Line : mStdOutList )
Out < < Line < < LineEnding ;
File . close ( ) ;
mAddonStdOutButton - > setEnabled ( true ) ;
}
else
ShowMessage ( tr ( " Error writing to %1 file '%2': \n %3 " ) . arg ( " stdout " ) . arg ( File . fileName ( ) , File . errorString ( ) ) ) ;
}
bool lcBlenderPreferences : : PromptCancel ( )
{
# ifndef QT_NO_PROCESS
if ( mProcess )
{
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " Cancel %1 Addon Install " ) . arg ( LC_PRODUCTNAME_STR ) ;
const QString & Header = " <b> " + tr ( " Are you sure you want to cancel the add on install ? " ) + " </b> " ;
2023-06-02 00:20:49 +02:00
int Exec = ShowMessage ( Header , Title , QString ( ) , QString ( ) , MBB_YES_NO , QMessageBox : : Question ) ;
if ( Exec = = QMessageBox : : Yes )
{
mProcess - > kill ( ) ;
delete mProcess ;
mProcess = nullptr ;
}
else
return false ;
}
# endif
mDialogCancelled = true ;
return true ;
}
void lcBlenderPreferences : : Update ( )
{
# ifndef QT_NO_PROCESS
if ( ! mProcess )
return ;
if ( mProcess - > state ( ) = = QProcess : : NotRunning )
ShowResult ( ) ;
# endif
QApplication : : processEvents ( ) ;
}
void lcBlenderPreferences : : Apply ( const int Response )
{
if ( Response = = QDialog : : Accepted )
{
if ( SettingsModified ( ) )
SaveSettings ( ) ;
}
else if ( mDialogCancelled )
{
if ( SettingsModified ( ) )
if ( PromptAccept ( ) )
SaveSettings ( ) ;
}
}
bool lcBlenderPreferences : : SettingsModified ( bool Update , const QString & Module )
{
if ( gAddonPreferences - > mDialogCancelled )
return false ;
int & Width = gAddonPreferences - > mImageWidth ;
int & Height = gAddonPreferences - > mImageHeight ;
double & Scale = gAddonPreferences - > mScale ;
bool ModuleMM = ! Module . isEmpty ( )
? Module = = QLatin1String ( " MM " )
: gAddonPreferences - > mImportMMActBox - > isChecked ( ) ;
bool Ok , Modified = ! QFileInfo ( lcGetProfileString ( LC_PROFILE_BLENDER_LDRAW_CONFIG_PATH ) ) . isReadable ( ) ;
qreal _Width = 0.0 , _Height = 0.0 , _Scale = 0.0 , _Value = 0.0 , _OldValue = 0.0 ;
QString OldValue ;
auto ItemChanged = [ ] ( qreal OldValue , qreal NewValue )
{
return NewValue > OldValue | | NewValue < OldValue ;
} ;
if ( ModuleMM )
{
for ( int LblIdx = 0 ; LblIdx < NumSettingsMM ( ) ; LblIdx + + )
{
// checkboxes
if ( LblIdx < LBL_BEVEL_SEGMENTS )
{
for ( int CtlIdx = 0 ; CtlIdx < gAddonPreferences - > mCheckBoxList . size ( ) ; CtlIdx + + )
{
OldValue = mBlenderSettingsMM [ LblIdx ] . value ;
if ( Update )
mBlenderSettingsMM [ LblIdx ] . value = QString : : number ( gAddonPreferences - > mCheckBoxList [ CtlIdx ] - > isChecked ( ) ) ;
Modified | = mBlenderSettingsMM [ LblIdx ] . value ! = OldValue ;
if ( LblIdx < LBL_VERBOSE_MM )
LblIdx + + ;
}
}
// lineedits
else if ( LblIdx < LBL_CHOSEN_LOGO )
{
for ( int CtlIdx = 0 ; CtlIdx < gAddonPreferences - > mLineEditList . size ( ) ; CtlIdx + + )
{
if ( CtlIdx = = CTL_RESOLUTION_WIDTH_EDIT )
{
_OldValue = Width ;
_Width = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toDouble ( & Ok ) ;
if ( Ok )
{
if ( Update )
{
Width = int ( _Width ) ;
mBlenderSettingsMM [ LblIdx ] . value = QString : : number ( Width ) ;
}
Modified | = ItemChanged ( _OldValue , _Width ) ;
}
}
else if ( CtlIdx = = CTL_RESOLUTION_HEIGHT_EDIT )
{
_OldValue = Height ;
_Height = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toDouble ( & Ok ) ;
if ( Ok )
{
if ( Update )
{
Height = int ( _Height ) ;
mBlenderSettingsMM [ LblIdx ] . value = QString : : number ( Height ) ;
}
Modified | = ItemChanged ( _OldValue , _Height ) ;
}
}
else if ( CtlIdx = = CTL_RENDER_PERCENTAGE_EDIT_MM )
{
_OldValue = Scale ;
_Scale = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toInt ( & Ok ) ;
if ( Ok )
{
if ( Update )
{
Scale = double ( _Scale / 100 ) ;
mBlenderSettingsMM [ LblIdx ] . value = QString : : number ( _Scale ) ;
}
Modified | = ItemChanged ( _OldValue , Scale ) ;
}
}
else
{
_OldValue = mBlenderSettingsMM [ LblIdx ] . value . toDouble ( ) ;
_Value = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toDouble ( & Ok ) ;
if ( Ok )
{
if ( Update )
mBlenderSettingsMM [ LblIdx ] . value = QString : : number ( _Value ) ;
Modified | = ItemChanged ( _OldValue , _Value ) ;
}
}
if ( LblIdx < LBL_STARTING_STEP_FRAME )
LblIdx + + ;
}
}
// comboboxes
else
{
for ( int CtlIdx = 0 ; CtlIdx < gAddonPreferences - > mComboBoxList . size ( ) ; CtlIdx + + )
{
OldValue = mBlenderSettingsMM [ LblIdx ] . value ;
2023-07-07 00:51:51 +02:00
const QString Value = gAddonPreferences - > mComboBoxList [ CtlIdx ] - > itemData ( gAddonPreferences - > mComboBoxList [ CtlIdx ] - > currentIndex ( ) ) . toString ( ) ;
2023-06-02 00:20:49 +02:00
if ( Update )
mBlenderSettingsMM [ LblIdx ] . value = Value ;
Modified | = Value ! = OldValue ;
LblIdx + + ;
}
}
}
}
else
{
// settings
for ( int LblIdx = 0 ; LblIdx < NumSettings ( ) ; LblIdx + + )
{
// checkboxes
if ( LblIdx < LBL_BEVEL_WIDTH )
{
for ( int CtlIdx = 0 ; CtlIdx < gAddonPreferences - > mCheckBoxList . size ( ) ; CtlIdx + + )
{
OldValue = mBlenderSettings [ LblIdx ] . value ;
if ( Update )
mBlenderSettings [ LblIdx ] . value = QString : : number ( gAddonPreferences - > mCheckBoxList [ CtlIdx ] - > isChecked ( ) ) ;
Modified | = mBlenderSettings [ LblIdx ] . value ! = OldValue ;
if ( LblIdx < LBL_VERBOSE )
LblIdx + + ;
}
}
// lineedits
else if ( LblIdx < LBL_COLOUR_SCHEME )
{
for ( int CtlIdx = 0 ; CtlIdx < gAddonPreferences - > mLineEditList . size ( ) ; CtlIdx + + )
{
if ( CtlIdx = = CTL_IMAGE_WIDTH_EDIT )
{
_OldValue = Width ;
_Width = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toDouble ( & Ok ) ;
if ( Ok )
{
if ( Update )
{
Width = int ( _Width ) ;
mBlenderSettings [ LblIdx ] . value = QString : : number ( Width ) ;
}
Modified | = ItemChanged ( _OldValue , _Width ) ;
}
}
else if ( CtlIdx = = CTL_IMAGE_HEIGHT_EDIT )
{
_OldValue = Height ;
_Height = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toDouble ( & Ok ) ;
if ( Ok )
{
if ( Update )
{
Height = int ( _Height ) ;
mBlenderSettings [ LblIdx ] . value = QString : : number ( Height ) ;
}
Modified | = ItemChanged ( _OldValue , _Height ) ;
}
}
else if ( CtlIdx = = CTL_RENDER_PERCENTAGE_EDIT )
{
_OldValue = Scale ;
_Scale = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toInt ( & Ok ) ;
if ( Ok )
{
if ( Update )
{
Scale = double ( _Scale / 100 ) ;
mBlenderSettings [ LblIdx ] . value = QString : : number ( _Scale ) ;
}
Modified | = ItemChanged ( _OldValue , Scale ) ;
}
}
else
{
if ( CtlIdx = = CTL_DEFAULT_COLOUR_EDIT )
{
_OldValue = lcGetColorIndex ( mBlenderSettings [ LblIdx ] . value . toInt ( ) ) ; // colour code
_Value = gAddonPreferences - > mLineEditList [ CtlIdx ] - > property ( " ColorIndex " ) . toInt ( & Ok ) ;
}
else
{
_OldValue = mBlenderSettings [ LblIdx ] . value . toDouble ( ) ;
_Value = gAddonPreferences - > mLineEditList [ CtlIdx ] - > text ( ) . toDouble ( & Ok ) ;
}
if ( Ok )
{
if ( Update )
{
if ( CtlIdx = = CTL_DEFAULT_COLOUR_EDIT )
{
mBlenderSettings [ LblIdx ] . value = QString : : number ( lcGetColorCode ( qint32 ( _Value ) ) ) ;
}
else
{
mBlenderSettings [ LblIdx ] . value = QString : : number ( _Value ) ;
}
}
Modified | = ItemChanged ( _OldValue , _Value ) ;
}
}
if ( LblIdx < LBL_RENDER_PERCENTAGE )
LblIdx + + ;
}
}
// comboboxes
else
{
for ( int CtlIdx = 0 ; CtlIdx < gAddonPreferences - > mComboBoxList . size ( ) ; CtlIdx + + )
{
OldValue = mBlenderSettings [ LblIdx ] . value ;
2023-07-07 00:51:51 +02:00
const QString Value = gAddonPreferences - > mComboBoxList [ CtlIdx ] - > itemData ( gAddonPreferences - > mComboBoxList [ CtlIdx ] - > currentIndex ( ) ) . toString ( ) ;
2023-06-02 00:20:49 +02:00
if ( Update )
mBlenderSettings [ LblIdx ] . value = Value ;
Modified | = Value ! = OldValue ;
LblIdx + + ;
}
}
}
}
// paths
for ( int LblIdx = 0 ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
OldValue = mBlenderPaths [ LblIdx ] . value ;
2023-07-07 00:51:51 +02:00
const QString Value = gAddonPreferences - > mPathLineEditList [ LblIdx ] - > text ( ) ;
2023-06-02 00:20:49 +02:00
if ( Update )
mBlenderPaths [ LblIdx ] . value = Value ;
Modified | = Value ! = OldValue ;
}
return Modified ;
}
void lcBlenderPreferences : : ResetSettings ( )
{
BlenderPaths const * Paths = mBlenderPaths ;
BlenderSettings const * Settings = mBlenderSettings ;
BlenderSettings const * SettingsMM = mBlenderSettingsMM ;
QDialog * Dialog = new QDialog ( this ) ;
Dialog - > setWindowTitle ( tr ( " Addon Reset " ) ) ;
Dialog - > setWhatsThis ( tr ( " Select how to reset settings. Choice is since last apply or system default. " ) ) ;
QVBoxLayout * Layout = new QVBoxLayout ( Dialog ) ;
QGroupBox * DlgGroup = new QGroupBox ( Dialog ) ;
QHBoxLayout * DlgLayout = new QHBoxLayout ( DlgGroup ) ;
QRadioButton * LastButton = new QRadioButton ( tr ( " Last Apply " ) ) ;
DlgLayout - > addWidget ( LastButton ) ;
QRadioButton * DefaultButton = new QRadioButton ( tr ( " System Default " ) ) ;
DlgLayout - > addWidget ( DefaultButton ) ;
DlgGroup - > setLayout ( DlgLayout ) ;
Layout - > addWidget ( DlgGroup ) ;
Dialog - > setLayout ( Layout ) ;
LastButton - > setChecked ( true ) ;
QDialogButtonBox ButtonBox ( QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel ,
Qt : : Horizontal , Dialog ) ;
Layout - > addWidget ( & ButtonBox ) ;
connect ( & ButtonBox , SIGNAL ( accepted ( ) ) , Dialog , SLOT ( accept ( ) ) ) ;
connect ( & ButtonBox , SIGNAL ( rejected ( ) ) , Dialog , SLOT ( reject ( ) ) ) ;
if ( Dialog - > exec ( ) = = QDialog : : Accepted )
{
if ( DefaultButton - > isChecked ( ) )
{
Paths = mDefaultPaths ;
Settings = mDefaultSettings ;
SettingsMM = mDefaultSettingsMM ;
}
}
mConfigured = ! lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) . isEmpty ( ) ;
mBlenderPaths [ PATH_BLENDER ] . value = lcGetProfileString ( LC_PROFILE_BLENDER_PATH ) ;
mBlenderVersion = lcGetProfileString ( LC_PROFILE_BLENDER_VERSION ) ;
mAddonVersion = lcGetProfileString ( LC_PROFILE_BLENDER_ADDON_VERSION ) ;
mBlenderVersionEdit - > setText ( mBlenderVersion ) ;
mAddonVersionEdit - > setText ( mAddonVersion ) ;
if ( mImportActBox - > isChecked ( ) )
{
disconnect ( mLineEditList [ CTL_IMAGE_HEIGHT_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
disconnect ( mLineEditList [ CTL_IMAGE_WIDTH_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
for ( int LblIdx = 0 ; LblIdx < NumSettings ( ) ; LblIdx + + )
{
if ( LblIdx < LBL_BEVEL_WIDTH )
{
for ( int CtlIdx = 0 ; CtlIdx < mCheckBoxList . size ( ) ; CtlIdx + + )
{
mCheckBoxList [ CtlIdx ] - > setChecked ( Settings [ LblIdx ] . value . toInt ( ) ) ;
if ( LblIdx < LBL_VERBOSE )
LblIdx + + ;
}
}
else if ( LblIdx < LBL_COLOUR_SCHEME )
{
for ( int CtlIdx = 0 ; CtlIdx < mLineEditList . size ( ) ; CtlIdx + + )
{
if ( CtlIdx = = CTL_IMAGE_WIDTH_EDIT )
mLineEditList [ CtlIdx ] - > setText ( QString : : number ( mImageWidth ) ) ;
else if ( CtlIdx = = CTL_IMAGE_HEIGHT_EDIT )
mLineEditList [ CtlIdx ] - > setText ( QString : : number ( mImageHeight ) ) ;
else if ( CtlIdx = = CTL_RENDER_PERCENTAGE_EDIT )
mLineEditList [ CtlIdx ] - > setText ( QString : : number ( mScale * 100 ) ) ;
else if ( CtlIdx = = CTL_DEFAULT_COLOUR_EDIT )
SetDefaultColor ( lcGetColorIndex ( Settings [ LBL_DEFAULT_COLOUR ] . value . toInt ( ) ) ) ;
else
mLineEditList [ CtlIdx ] - > setText ( Settings [ LblIdx ] . value ) ;
if ( LblIdx < LBL_RENDER_PERCENTAGE )
LblIdx + + ;
}
}
else
{
for ( int CtlIdx = 0 ; CtlIdx < mComboBoxList . size ( ) ; CtlIdx + + )
{
mComboBoxList [ CtlIdx ] - > setCurrentIndex ( int ( mComboBoxList [ CtlIdx ] - > findData ( QVariant : : fromValue ( Settings [ LblIdx ] . value ) ) ) ) ;
LblIdx + + ;
}
}
}
for ( int LblIdx = 0 ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
mPathLineEditList [ LblIdx ] - > setText ( Paths [ LblIdx ] . value ) ;
}
connect ( mLineEditList [ CTL_IMAGE_HEIGHT_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
connect ( mLineEditList [ CTL_IMAGE_WIDTH_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
}
else if ( mImportMMActBox - > isChecked ( ) )
{
disconnect ( mLineEditList [ CTL_RESOLUTION_HEIGHT_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
disconnect ( mLineEditList [ CTL_RESOLUTION_WIDTH_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
for ( int LblIdx = 0 ; LblIdx < NumSettingsMM ( ) ; LblIdx + + )
{
if ( LblIdx < LBL_BEVEL_SEGMENTS )
{
for ( int CtlIdx = 0 ; CtlIdx < mCheckBoxList . size ( ) ; CtlIdx + + )
{
mCheckBoxList [ CtlIdx ] - > setChecked ( SettingsMM [ LblIdx ] . value . toInt ( ) ) ;
if ( LblIdx < LBL_VERBOSE_MM )
LblIdx + + ;
}
}
else if ( LblIdx < LBL_CHOSEN_LOGO )
{
for ( int CtlIdx = 0 ; CtlIdx < mLineEditList . size ( ) ; CtlIdx + + )
{
if ( CtlIdx = = CTL_RESOLUTION_WIDTH_EDIT )
mLineEditList [ CtlIdx ] - > setText ( QString : : number ( mImageWidth ) ) ;
else if ( CtlIdx = = CTL_RESOLUTION_HEIGHT_EDIT )
mLineEditList [ CtlIdx ] - > setText ( QString : : number ( mImageHeight ) ) ;
else if ( CtlIdx = = CTL_RENDER_PERCENTAGE_EDIT_MM )
mLineEditList [ CtlIdx ] - > setText ( QString : : number ( mScale * 100 ) ) ;
else
mLineEditList [ CtlIdx ] - > setText ( SettingsMM [ LblIdx ] . value ) ;
if ( LblIdx < LBL_STARTING_STEP_FRAME )
LblIdx + + ;
}
}
else
{
for ( int CtlIdx = 0 ; CtlIdx < mComboBoxList . size ( ) ; CtlIdx + + )
{
mComboBoxList [ CtlIdx ] - > setCurrentIndex ( int ( mComboBoxList [ CtlIdx ] - > findData ( QVariant : : fromValue ( SettingsMM [ LblIdx ] . value ) ) ) ) ;
LblIdx + + ;
}
}
}
for ( int LblIdx = 0 ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
mPathLineEditList [ LblIdx ] - > setText ( Paths [ LblIdx ] . value ) ;
}
connect ( mLineEditList [ CTL_RESOLUTION_HEIGHT_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
connect ( mLineEditList [ CTL_RESOLUTION_WIDTH_EDIT ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
}
emit SettingChangedSig ( true ) ;
}
void lcBlenderPreferences : : LoadSettings ( )
{
2024-04-28 02:19:34 +02:00
QStringList const & DataPathList = QStandardPaths : : standardLocations ( QStandardPaths : : AppLocalDataLocation ) ;
2023-06-02 00:20:49 +02:00
gAddonPreferences - > mDataDir = DataPathList . first ( ) ;
if ( QFileInfo ( lcGetProfileString ( LC_PROFILE_BLENDER_PATH ) ) . isReadable ( ) )
{
if ( lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) . isEmpty ( ) )
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , QLatin1String ( LC_BLENDER_ADDON_IMPORT_MODULE ) ) ;
}
else
{
lcSetProfileString ( LC_PROFILE_BLENDER_PATH , QString ( ) ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , QString ( ) ) ;
}
if ( ! QDir ( QString ( " %1/Blender/addons/%2 " ) . arg ( gAddonPreferences - > mDataDir ) . arg ( LC_BLENDER_ADDON_FOLDER_STR ) ) . isReadable ( ) )
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , QString ( ) ) ;
if ( ! NumPaths ( ) )
{
2023-07-07 00:51:51 +02:00
const QString DefaultBlendFile = QString ( " %1/Blender/config/%2 " ) . arg ( gAddonPreferences - > mDataDir ) . arg ( LC_BLENDER_ADDON_BLEND_FILE ) ;
2023-06-02 00:20:49 +02:00
QStringList const AddonPaths = QStringList ( )
/* PATH_BLENDER */ < < lcGetProfileString ( LC_PROFILE_BLENDER_PATH )
/* PATH_BLENDFILE */ < < ( QFileInfo ( DefaultBlendFile ) . exists ( ) ? DefaultBlendFile : QString ( ) )
/* PATH_ENVIRONMENT */ < < QString ( )
/* PATH_LDCONFIG */ < < lcGetProfileString ( LC_PROFILE_COLOR_CONFIG )
/* PATH_LDRAW */ < < QFileInfo ( lcGetProfileString ( LC_PROFILE_PARTS_LIBRARY ) ) . absolutePath ( )
/* PATH_LSYNTH */ < < QString ( )
/* PATH_STUD_LOGO */ < < QString ( )
/* PATH_STUDIO_LDRAW */ < < QString ( ) ;
for ( int LblIdx = 0 ; LblIdx < NumPaths ( DEFAULT_SETTINGS ) ; LblIdx + + )
{
mBlenderPaths [ LblIdx ] =
{
mDefaultPaths [ LblIdx ] . key ,
mDefaultPaths [ LblIdx ] . key_mm ,
QDir : : toNativeSeparators ( AddonPaths . at ( LblIdx ) ) ,
mDefaultPaths [ LblIdx ] . label ,
mDefaultPaths [ LblIdx ] . tooltip
} ;
}
}
if ( ! NumSettings ( ) )
{
for ( int LblIdx = 0 ; LblIdx < NumSettings ( DEFAULT_SETTINGS ) ; LblIdx + + )
{
mBlenderSettings [ LblIdx ] =
{
mDefaultSettings [ LblIdx ] . key ,
mDefaultSettings [ LblIdx ] . value ,
mDefaultSettings [ LblIdx ] . label ,
mDefaultSettings [ LblIdx ] . tooltip
} ;
}
}
if ( ! NumSettingsMM ( ) )
{
for ( int LblIdx = 0 ; LblIdx < NumSettingsMM ( DEFAULT_SETTINGS ) ; LblIdx + + )
{
mBlenderSettingsMM [ LblIdx ] =
{
mDefaultSettingsMM [ LblIdx ] . key ,
mDefaultSettingsMM [ LblIdx ] . value ,
mDefaultSettingsMM [ LblIdx ] . label ,
mDefaultSettingsMM [ LblIdx ] . tooltip
} ;
}
}
QFileInfo BlenderConfigFileInfo ( lcGetProfileString ( LC_PROFILE_BLENDER_LDRAW_CONFIG_PATH ) ) ;
bool ConfigFileExists = BlenderConfigFileInfo . exists ( ) ;
if ( ConfigFileExists )
{
QSettings Settings ( BlenderConfigFileInfo . absoluteFilePath ( ) , QSettings : : IniFormat ) ;
for ( int LblIdx = 1 /*skip blender executable*/ ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
if ( LblIdx = = PATH_STUDIO_LDRAW )
continue ;
2023-07-07 00:51:51 +02:00
const QString & Key = QString ( " %1/%2 " ) . arg ( LC_BLENDER_ADDON , mBlenderPaths [ LblIdx ] . key ) ;
const QString & Value = Settings . value ( Key , QString ( ) ) . toString ( ) ;
2023-06-02 00:20:49 +02:00
if ( QFileInfo ( Value ) . exists ( ) )
{
mBlenderPaths [ LblIdx ] . value = QDir : : toNativeSeparators ( Value ) ;
}
}
for ( int LblIdx = 1 /*skip blender executable*/ ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
if ( LblIdx = = PATH_LSYNTH | | LblIdx = = PATH_STUD_LOGO )
continue ;
2023-07-07 00:51:51 +02:00
const QString & Key = QString ( " %1/%2 " ) . arg ( LC_BLENDER_ADDON_MM , mBlenderPaths [ LblIdx ] . key_mm ) ;
const QString & Value = Settings . value ( Key , QString ( ) ) . toString ( ) ;
2023-06-02 00:20:49 +02:00
if ( QFileInfo ( Value ) . exists ( ) )
{
mBlenderPaths [ LblIdx ] . value = QDir : : toNativeSeparators ( Value ) ;
}
}
for ( int LblIdx = 0 ; LblIdx < NumSettings ( ) ; LblIdx + + )
{
2023-07-07 00:51:51 +02:00
const QString & Key = QString ( " %1/%2 " ) . arg ( LC_BLENDER_ADDON , mBlenderSettings [ LblIdx ] . key ) ;
const QString & Value = Settings . value ( Key , QString ( ) ) . toString ( ) ;
2023-06-02 00:20:49 +02:00
if ( ! Value . isEmpty ( ) )
{
mBlenderSettings [ LblIdx ] . value = Value = = " True " ? " 1 " : Value = = " False " ? " 0 " : Value ;
}
if ( LblIdx = = LBL_IMAGE_WIDTH | | LblIdx = = LBL_IMAGE_HEIGHT | | LblIdx = = LBL_RENDER_PERCENTAGE )
{
2023-07-07 00:51:51 +02:00
const QString & Label = mDefaultSettings [ LblIdx ] . label ;
2023-06-02 00:20:49 +02:00
mBlenderSettings [ LblIdx ] . label = QString ( " %1 - Setting (%2) " ) . arg ( Label ) . arg ( Value ) ;
}
}
for ( int LblIdx = 0 ; LblIdx < NumSettingsMM ( ) ; LblIdx + + )
{
2023-07-07 00:51:51 +02:00
const QString & Key = QString ( " %1/%2 " ) . arg ( LC_BLENDER_ADDON_MM , mBlenderSettingsMM [ LblIdx ] . key ) ;
const QString & Value = Settings . value ( Key , QString ( ) ) . toString ( ) ;
2023-06-02 00:20:49 +02:00
if ( ! Value . isEmpty ( ) )
{
mBlenderSettingsMM [ LblIdx ] . value = Value = = " True " ? " 1 " : Value = = " False " ? " 0 " : Value ;
}
if ( LblIdx = = LBL_RENDER_PERCENTAGE_MM | | LblIdx = = LBL_RESOLUTION_WIDTH | | LblIdx = = LBL_RESOLUTION_HEIGHT )
{
2023-07-07 00:51:51 +02:00
const QString & Label = mDefaultSettingsMM [ LblIdx ] . label ;
2023-06-02 00:20:49 +02:00
mBlenderSettingsMM [ LblIdx ] . label = QString ( " %1 - Setting (%2) " ) . arg ( Label ) . arg ( Value ) ;
}
}
}
else
{
2023-07-07 00:51:51 +02:00
const QString LogFile = QString ( " %1/Blender/stdout-blender-addon-install " ) . arg ( gAddonPreferences - > mDataDir ) ;
2023-06-02 00:20:49 +02:00
if ( QFileInfo ( LogFile ) . isReadable ( ) )
{
QFile File ( LogFile ) ;
if ( File . open ( QFile : : ReadOnly | QFile : : Text ) )
{
QByteArray Ba = File . readAll ( ) ;
File . close ( ) ;
QString Errors ;
gAddonPreferences - > mProgressBar = nullptr ;
gAddonPreferences - > ReadStdOut ( QString ( Ba ) , Errors ) ;
}
else
{
ShowMessage ( tr ( " Failed to open log file: %1: \n %2 " )
. arg ( File . fileName ( ) )
. arg ( File . errorString ( ) ) ) ;
}
}
}
mBlenderSettings [ LBL_IMAGE_WIDTH ] . value = QString : : number ( gAddonPreferences - > mImageWidth ) ;
mBlenderSettings [ LBL_IMAGE_HEIGHT ] . value = QString : : number ( gAddonPreferences - > mImageHeight ) ;
mBlenderSettings [ LBL_RENDER_PERCENTAGE ] . value = QString : : number ( gAddonPreferences - > mScale * 100 ) ;
mBlenderSettingsMM [ LBL_RESOLUTION_WIDTH ] . value = QString : : number ( gAddonPreferences - > mImageWidth ) ;
mBlenderSettingsMM [ LBL_RESOLUTION_HEIGHT ] . value = QString : : number ( gAddonPreferences - > mImageHeight ) ;
mBlenderSettingsMM [ LBL_RENDER_PERCENTAGE_MM ] . value = QString : : number ( gAddonPreferences - > mScale * 100 ) ;
mBlenderPaths [ PATH_BLENDER ] . value = lcGetProfileString ( LC_PROFILE_BLENDER_PATH ) ;
gAddonPreferences - > mBlenderVersion = lcGetProfileString ( LC_PROFILE_BLENDER_VERSION ) ;
gAddonPreferences - > mAddonVersion = lcGetProfileString ( LC_PROFILE_BLENDER_ADDON_VERSION ) ;
}
void lcBlenderPreferences : : SaveSettings ( )
{
if ( ! NumSettings ( ) | | ! NumSettingsMM ( ) )
LoadSettings ( ) ;
2023-07-07 00:51:51 +02:00
const QString BlenderConfigDir = QString ( " %1/Blender/setup/addon_setup/config " ) . arg ( gAddonPreferences - > mDataDir ) ;
2023-06-02 00:20:49 +02:00
QString Key , Value = mBlenderPaths [ PATH_BLENDER ] . value ;
if ( Value . isEmpty ( ) )
Value = gAddonPreferences - > mPathLineEditList [ PATH_BLENDER ] - > text ( ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_PATH , QDir : : toNativeSeparators ( Value ) ) ;
Value . clear ( ) ;
if ( ! gAddonPreferences - > mBlenderVersion . isEmpty ( ) )
Value = gAddonPreferences - > mBlenderVersion ;
if ( ! gAddonPreferences - > mAddonVersion . isEmpty ( ) )
{
gAddonPreferences - > mModulesBox - > setEnabled ( true ) ;
gAddonPreferences - > mAddonVersionEdit - > setText ( gAddonPreferences - > mAddonVersion ) ;
}
lcSetProfileString ( LC_PROFILE_BLENDER_VERSION , Value ) ;
2023-07-07 00:51:51 +02:00
Value = lcGetProfileString ( LC_PROFILE_BLENDER_LDRAW_CONFIG_PATH ) . isEmpty ( ) ? QString ( " %1/%2 " ) . arg ( BlenderConfigDir ) . arg ( LC_BLENDER_ADDON_CONFIG_FILE ) : lcGetProfileString ( LC_PROFILE_BLENDER_LDRAW_CONFIG_PATH ) ;
2023-06-02 00:20:49 +02:00
lcSetProfileString ( LC_PROFILE_BLENDER_LDRAW_CONFIG_PATH , QDir : : toNativeSeparators ( Value ) ) ;
QString searchDirectoriesKey ;
QString parameterFileKey = QLatin1String ( " ParameterFile " ) ;
QString ParameterFile = QString ( " %1/%2 " ) . arg ( BlenderConfigDir ) . arg ( LC_BLENDER_ADDON_PARAMS_FILE ) ;
QSettings Settings ( Value , QSettings : : IniFormat ) ;
auto concludeSettingsGroup = [ & ] ( )
{
if ( ! QFileInfo ( ParameterFile ) . exists ( ) )
ExportParameterFile ( ) ;
Value = QDir : : toNativeSeparators ( QFileInfo ( lcGetProfileString ( LC_PROFILE_PARTS_LIBRARY ) ) . absolutePath ( ) ) ;
Settings . setValue ( searchDirectoriesKey , QVariant ( Value ) ) ;
Settings . endGroup ( ) ;
} ;
Settings . beginGroup ( LC_BLENDER_ADDON ) ;
for ( int LblIdx = 1 /*skip blender executable*/ ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
if ( LblIdx = = PATH_STUDIO_LDRAW )
continue ;
Key = mBlenderPaths [ LblIdx ] . key ;
Value = QDir : : toNativeSeparators ( mBlenderPaths [ LblIdx ] . value ) ;
2023-07-30 21:22:19 +02:00
if ( Settings . contains ( Key ) )
Settings . setValue ( Key , QVariant ( Value ) ) ;
2023-06-02 00:20:49 +02:00
}
for ( int LblIdx = 0 ; LblIdx < NumSettings ( ) ; LblIdx + + )
{
if ( LblIdx = = LBL_KEEP_ASPECT_RATIO )
{
continue ;
}
else if ( LblIdx < LBL_BEVEL_WIDTH )
{
Value = mBlenderSettings [ LblIdx ] . value = = " 1 " ? " True " : " False " ;
}
else if ( LblIdx > LBL_VERBOSE )
{
if ( LblIdx = = LBL_FLEX_PARTS_SOURCE | | LblIdx = = LBL_POSITION_OBJECT )
Value = mBlenderSettings [ LblIdx ] . value = = " 1 " ? " True " : " False " ;
else
Value = mBlenderSettings [ LblIdx ] . value ;
}
Key = mBlenderSettings [ LblIdx ] . key ;
2023-07-30 21:22:19 +02:00
if ( Settings . contains ( Key ) )
Settings . setValue ( Key , QVariant ( Value ) ) ;
2023-06-02 00:20:49 +02:00
}
Settings . setValue ( parameterFileKey , QVariant ( QDir : : toNativeSeparators ( ParameterFile ) ) ) ;
searchDirectoriesKey = QLatin1String ( " additionalSearchDirectories " ) ;
concludeSettingsGroup ( ) ;
Settings . beginGroup ( LC_BLENDER_ADDON_MM ) ;
for ( int LblIdx = 1 /*skip blender executable*/ ; LblIdx < NumPaths ( ) ; LblIdx + + )
{
if ( LblIdx = = PATH_LSYNTH | | LblIdx = = PATH_STUD_LOGO )
continue ;
Key = mBlenderPaths [ LblIdx ] . key_mm ;
Value = QDir : : toNativeSeparators ( mBlenderPaths [ LblIdx ] . value ) ;
2023-07-30 21:22:19 +02:00
if ( Settings . contains ( Key ) )
Settings . setValue ( Key , QVariant ( Value ) ) ;
2023-06-02 00:20:49 +02:00
}
for ( int LblIdx = 0 ; LblIdx < NumSettingsMM ( ) ; LblIdx + + )
{
if ( LblIdx = = LBL_KEEP_ASPECT_RATIO_MM )
{
continue ;
}
else if ( LblIdx < LBL_BEVEL_SEGMENTS )
{
Value = mBlenderSettingsMM [ LblIdx ] . value = = " 1 " ? " True " : " False " ;
}
else if ( LblIdx > LBL_VERBOSE_MM )
{
Value = mBlenderSettingsMM [ LblIdx ] . value ;
}
Key = mBlenderSettingsMM [ LblIdx ] . key ;
2023-07-30 21:22:19 +02:00
if ( Settings . contains ( Key ) )
Settings . setValue ( Key , QVariant ( Value ) ) ;
2023-06-02 00:20:49 +02:00
}
searchDirectoriesKey = QLatin1String ( " additionalSearchPaths " ) ;
concludeSettingsGroup ( ) ;
2023-07-07 00:51:51 +02:00
const QString preferredImportModule = gAddonPreferences - > mImportActBox - > isChecked ( ) ? QString ( " TN " ) : gAddonPreferences - > mImportMMActBox - > isChecked ( ) ? QString ( " MM " ) : QString ( ) ;
2023-06-02 00:20:49 +02:00
if ( preferredImportModule ! = lcGetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE ) )
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , preferredImportModule ) ;
}
void lcBlenderPreferences : : EnableImportModule ( )
{
QString saveImportModule , preferredImportModule ;
if ( sender ( ) = = mImportActBox & & mImportActBox - > isChecked ( ) )
{
preferredImportModule = QLatin1String ( " TN " ) ;
if ( mImportMMActBox - > isChecked ( ) )
saveImportModule = QLatin1String ( " MM " ) ;
mImportMMActBox - > setChecked ( false ) ;
}
else if ( sender ( ) = = mImportMMActBox & & mImportMMActBox - > isChecked ( ) )
{
preferredImportModule = QLatin1String ( " MM " ) ;
if ( mImportActBox - > isChecked ( ) )
saveImportModule = QLatin1String ( " TN " ) ;
mImportActBox - > setChecked ( false ) ;
}
if ( preferredImportModule . isEmpty ( ) )
return ;
if ( SettingsModified ( true , saveImportModule ) )
SaveSettings ( ) ;
lcSetProfileString ( LC_PROFILE_BLENDER_IMPORT_MODULE , preferredImportModule ) ;
if ( mImportMMActBox - > isChecked ( ) )
InitPathsAndSettingsMM ( ) ;
else
InitPathsAndSettings ( ) ;
ConfigureBlenderAddon ( false , false , true ) ;
}
int lcBlenderPreferences : : NumSettings ( bool DefaultSettings )
{
int Size = 0 ;
if ( ! mBlenderSettings [ 0 ] . key . isEmpty ( ) | | DefaultSettings )
Size = sizeof ( mBlenderSettings ) / sizeof ( mBlenderSettings [ 0 ] ) ;
return Size ;
}
int lcBlenderPreferences : : NumSettingsMM ( bool DefaultSettings )
{
int Size = 0 ;
if ( ! mBlenderSettingsMM [ 0 ] . key . isEmpty ( ) | | DefaultSettings )
Size = sizeof ( mBlenderSettingsMM ) / sizeof ( mBlenderSettingsMM [ 0 ] ) ;
return Size ;
}
int lcBlenderPreferences : : NumPaths ( bool DefaultSettings )
{
int Size = 0 ;
if ( ! mBlenderPaths [ 0 ] . key . isEmpty ( ) | | DefaultSettings )
Size = sizeof ( mBlenderPaths ) / sizeof ( mBlenderPaths [ 0 ] ) ;
return Size ;
}
void lcBlenderPreferences : : ShowPathsGroup ( )
{
if ( mPathsBox - > isHidden ( ) )
mPathsBox - > show ( ) ;
else
mPathsBox - > hide ( ) ;
mContent - > adjustSize ( ) ;
}
void lcBlenderPreferences : : ColorButtonClicked ( bool )
{
int ColorIndex = mLineEditList [ CTL_DEFAULT_COLOUR_EDIT ] - > property ( " ColorIndex " ) . toInt ( ) ;
QWidget * Parent = mLineEditList [ CTL_DEFAULT_COLOUR_EDIT ] ;
lcColorPickerPopup * Popup = new lcColorPickerPopup ( Parent , ColorIndex ) ;
connect ( Popup , SIGNAL ( selected ( int ) ) , SLOT ( SetDefaultColor ( int ) ) ) ;
Popup - > setMinimumSize ( 300 , 200 ) ;
2024-04-28 02:19:34 +02:00
# if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QScreen * Screen = screen ( ) ;
const QRect DesktopGeom = Screen ? Screen - > geometry ( ) : QRect ( ) ;
# else
2023-06-02 00:20:49 +02:00
const QRect DesktopGeom = QApplication : : desktop ( ) - > geometry ( ) ;
2024-04-28 02:19:34 +02:00
# endif
2023-06-02 00:20:49 +02:00
QPoint Pos = Parent - > mapToGlobal ( Parent - > rect ( ) . bottomLeft ( ) ) ;
if ( Pos . x ( ) < DesktopGeom . left ( ) )
Pos . setX ( DesktopGeom . left ( ) ) ;
if ( Pos . y ( ) < DesktopGeom . top ( ) )
Pos . setY ( DesktopGeom . top ( ) ) ;
if ( ( Pos . x ( ) + Popup - > width ( ) ) > DesktopGeom . width ( ) )
Pos . setX ( DesktopGeom . width ( ) - Popup - > width ( ) ) ;
if ( ( Pos . y ( ) + Popup - > height ( ) ) > DesktopGeom . bottom ( ) )
Pos . setY ( DesktopGeom . bottom ( ) - Popup - > height ( ) ) ;
Popup - > move ( Pos ) ;
Popup - > setFocus ( ) ;
Popup - > show ( ) ;
}
void lcBlenderPreferences : : SetDefaultColor ( int ColorIndex )
{
QImage Image ( 12 , 12 , QImage : : Format_ARGB32 ) ;
Image . fill ( 0 ) ;
lcColor * Colour = & gColorList [ ColorIndex ] ;
QPainter Painter ( & Image ) ;
Painter . setCompositionMode ( QPainter : : CompositionMode_Source ) ;
Painter . setPen ( Qt : : darkGray ) ;
Painter . setBrush ( QColor : : fromRgbF ( qreal ( Colour - > Value [ 0 ] ) , qreal ( Colour - > Value [ 1 ] ) , qreal ( Colour - > Value [ 2 ] ) ) ) ;
Painter . drawRect ( 0 , 0 , Image . width ( ) - 1 , Image . height ( ) - 1 ) ;
Painter . end ( ) ;
int const ColourCode = lcGetColorCode ( ColorIndex ) ;
mLineEditList [ CTL_DEFAULT_COLOUR_EDIT ] - > setText ( QString ( " %1 (%2) " ) . arg ( Colour - > Name ) . arg ( ColourCode ) ) ;
mLineEditList [ CTL_DEFAULT_COLOUR_EDIT ] - > setProperty ( " ColorIndex " , QVariant : : fromValue ( ColorIndex ) ) ;
mDefaultColourEditAction - > setIcon ( QPixmap : : fromImage ( Image ) ) ;
mDefaultColourEditAction - > setToolTip ( tr ( " Select Colour " ) ) ;
bool Change = mBlenderSettings [ LBL_DEFAULT_COLOUR ] . value ! = QString : : number ( ColourCode ) ;
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
void lcBlenderPreferences : : BrowseBlender ( bool )
{
for ( int LblIdx = 0 ; LblIdx < NumPaths ( ) ; + + LblIdx )
{
if ( sender ( ) = = mPathBrowseButtonList . at ( LblIdx ) )
{
2023-07-07 00:51:51 +02:00
const QString BlenderPath = QDir : : toNativeSeparators ( mBlenderPaths [ LblIdx ] . value ) . toLower ( ) ;
2023-06-02 00:20:49 +02:00
QFileDialog FileDialog ( nullptr ) ;
FileDialog . setWindowTitle ( tr ( " Locate %1 " ) . arg ( mBlenderPaths [ LblIdx ] . label ) ) ;
if ( LblIdx < PATH_LDRAW )
FileDialog . setFileMode ( QFileDialog : : ExistingFile ) ;
else
FileDialog . setFileMode ( QFileDialog : : Directory ) ;
if ( ! BlenderPath . isEmpty ( ) )
FileDialog . setDirectory ( QFileInfo ( BlenderPath ) . absolutePath ( ) ) ;
if ( FileDialog . exec ( ) )
{
QStringList SelectedPathList = FileDialog . selectedFiles ( ) ;
if ( SelectedPathList . size ( ) = = 1 )
{
QFileInfo PathInfo ( SelectedPathList . at ( 0 ) ) ;
if ( PathInfo . exists ( ) )
{
2023-07-07 00:51:51 +02:00
const QString SelectedPath = QDir : : toNativeSeparators ( PathInfo . absoluteFilePath ( ) ) . toLower ( ) ;
2023-06-02 00:20:49 +02:00
mPathLineEditList [ LblIdx ] - > setText ( SelectedPathList . at ( 0 ) ) ;
if ( LblIdx ! = PATH_BLENDER )
{
bool Change = false ;
if ( mImportMMActBox - > isChecked ( ) )
Change = QDir : : toNativeSeparators ( mBlenderSettingsMM [ LblIdx ] . value ) . toLower ( ) ! = SelectedPath ;
else
Change = QDir : : toNativeSeparators ( mBlenderSettings [ LblIdx ] . value ) . toLower ( ) ! = SelectedPath ;
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
if ( LblIdx = = PATH_BLENDER & & BlenderPath ! = SelectedPath )
{
mBlenderPaths [ LblIdx ] . value = SelectedPath ;
UpdateBlenderAddon ( ) ;
}
}
}
}
}
}
}
void lcBlenderPreferences : : SizeChanged ( const QString & Value )
{
const bool ImportMM = mImportMMActBox - > isChecked ( ) ;
const int Keep_Aspect_Ratio = ImportMM ? int ( CTL_KEEP_ASPECT_RATIO_BOX_MM ) : int ( CTL_KEEP_ASPECT_RATIO_BOX ) ;
const int Width_Edit = ImportMM ? int ( CTL_RESOLUTION_WIDTH_EDIT ) : int ( CTL_IMAGE_WIDTH_EDIT ) ;
const int Height_Edit = ImportMM ? int ( CTL_RESOLUTION_HEIGHT_EDIT ) : int ( CTL_IMAGE_HEIGHT_EDIT ) ;
BlenderSettings const * Settings = ImportMM ? mBlenderSettingsMM : mBlenderSettings ;
bool Change = false ;
int NewValue = Value . toInt ( ) ;
if ( mCheckBoxList [ Keep_Aspect_Ratio ] - > isChecked ( ) )
{
if ( sender ( ) = = mLineEditList [ Width_Edit ] )
{
disconnect ( mLineEditList [ Height_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
2023-07-07 00:51:51 +02:00
const QString Height = QString : : number ( qRound ( double ( mImageHeight * NewValue / mImageWidth ) ) ) ;
2023-06-02 00:20:49 +02:00
mLineEditList [ Height_Edit ] - > setText ( Height ) ;
Change = Settings [ Height_Edit ] . value ! = Height ;
connect ( mLineEditList [ Height_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
}
else if ( sender ( ) = = mLineEditList [ Height_Edit ] )
{
disconnect ( mLineEditList [ Width_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
2023-07-07 00:51:51 +02:00
const QString Width = QString : : number ( qRound ( double ( NewValue * mImageWidth / mImageHeight ) ) ) ;
2023-06-02 00:20:49 +02:00
mLineEditList [ Width_Edit ] - > setText ( Width ) ;
Change = Settings [ Height_Edit ] . value ! = Width ;
connect ( mLineEditList [ Width_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
}
// Change is provided here for consistency only as ImageWidth,
// ImageHeight, and RenderPercentage are passed at the render command
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
}
void lcBlenderPreferences : : SetModelSize ( bool Update )
{
const bool ImportMM = mImportMMActBox - > isChecked ( ) ;
const int Crop_Image = ImportMM ? int ( CTL_CROP_IMAGE_BOX_MM ) : int ( CTL_CROP_IMAGE_BOX ) ;
const int Add_Environment = ImportMM ? int ( CTL_ADD_ENVIRONMENT_BOX_MM ) : int ( CTL_ADD_ENVIRONMENT_BOX ) ;
const int Trans_Background = ImportMM ? int ( CTL_TRANSPARENT_BACKGROUND_BOX_MM ) : int ( CTL_TRANSPARENT_BACKGROUND_BOX ) ;
const int Keep_Aspect_Ratio = ImportMM ? int ( CTL_KEEP_ASPECT_RATIO_BOX_MM ) : int ( CTL_KEEP_ASPECT_RATIO_BOX ) ;
const int Width_Edit = ImportMM ? int ( CTL_RESOLUTION_WIDTH_EDIT ) : int ( CTL_IMAGE_WIDTH_EDIT ) ;
const int Height_Edit = ImportMM ? int ( CTL_RESOLUTION_HEIGHT_EDIT ) : int ( CTL_IMAGE_HEIGHT_EDIT ) ;
const int Crop_Image_Label = ImportMM ? int ( LBL_CROP_IMAGE_MM ) : int ( LBL_CROP_IMAGE ) ;
2023-07-07 00:51:51 +02:00
const QString CropImageLabel = mSettingLabelList [ Crop_Image_Label ] - > text ( ) ;
2023-06-02 00:20:49 +02:00
int ImageWidth = mImageWidth ;
int ImageHeight = mImageHeight ;
const bool CropImage = mCheckBoxList [ Crop_Image ] - > isChecked ( ) ;
lcModel * Model = lcGetActiveProject ( ) - > GetActiveModel ( ) ;
if ( Model )
{
struct NativeImage
{
QImage RenderedImage ;
QRect Bounds ;
} ;
std : : vector < NativeImage > Images ;
Images . push_back ( NativeImage ( ) ) ;
NativeImage & Image = Images . back ( ) ;
Image . RenderedImage = Model - > GetStepImage ( false , ImageWidth , ImageHeight , Model - > GetCurrentStep ( ) ) ;
auto CalculateImageBounds = [ ] ( NativeImage & Image )
{
QImage & RenderedImage = Image . RenderedImage ;
int Width = RenderedImage . width ( ) ;
int Height = RenderedImage . height ( ) ;
int MinX = Width ;
int MinY = Height ;
int MaxX = 0 ;
int MaxY = 0 ;
for ( int x = 0 ; x < Width ; x + + )
{
for ( int y = 0 ; y < Height ; y + + )
{
if ( qAlpha ( RenderedImage . pixel ( x , y ) ) )
{
MinX = qMin ( x , MinX ) ;
MinY = qMin ( y , MinY ) ;
MaxX = qMax ( x , MaxX ) ;
MaxY = qMax ( y , MaxY ) ;
}
}
}
Image . Bounds = QRect ( QPoint ( MinX , MinY ) , QPoint ( MaxX , MaxY ) ) ;
} ;
QtConcurrent : : blockingMap ( Images , CalculateImageBounds ) ;
ImageWidth = Image . Bounds . width ( ) ;
ImageHeight = Image . Bounds . height ( ) ;
}
mSettingLabelList [ Crop_Image_Label ] - > setText ( QString ( " %1 (%2 x %3) " ) . arg ( CropImageLabel ) . arg ( ImageWidth ) . arg ( ImageHeight ) ) ;
if ( CropImage )
{
bool Conflict [ 3 ] ;
if ( ( Conflict [ 1 ] = mCheckBoxList [ Add_Environment ] - > isChecked ( ) ) )
mCheckBoxList [ Add_Environment ] - > setChecked ( ! CropImage ) ;
if ( ( Conflict [ 2 ] = ! mCheckBoxList [ Trans_Background ] - > isChecked ( ) ) )
mCheckBoxList [ Trans_Background ] - > setChecked ( CropImage ) ;
if ( ( Conflict [ 0 ] = mCheckBoxList [ Keep_Aspect_Ratio ] - > isChecked ( ) ) )
mCheckBoxList [ Keep_Aspect_Ratio ] - > setChecked ( ! CropImage ) ;
if ( Conflict [ 0 ] | | Conflict [ 1 ] | | Conflict [ 2 ] )
{
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " LDraw Render Settings Conflict " ) ;
const QString & Header = " <b> " + tr ( " Crop image configuration settings conflict were resolved. " ) + " </b> " ;
const QString & Body = QString ( " %1%2%3 " ) . arg ( Conflict [ 0 ] ? tr ( " Keep aspect ratio set to false.<br> " ) : " " ) . arg ( Conflict [ 1 ] ? tr ( " Add environment (backdrop and base plane) set to false.<br> " ) : " " ) . arg ( Conflict [ 2 ] ? tr ( " Transparent background set to true.<br> " ) : " " ) ;
2023-06-02 00:20:49 +02:00
ShowMessage ( Header , Title , Body , QString ( ) , MBB_OK , QMessageBox : : Information ) ;
}
}
disconnect ( mLineEditList [ Width_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
disconnect ( mLineEditList [ Height_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
2023-07-07 00:51:51 +02:00
const QString Width = QString : : number ( CropImage ? ImageWidth : mImageWidth ) ;
const QString Height = QString : : number ( CropImage ? ImageHeight : mImageHeight ) ;
2023-06-02 00:20:49 +02:00
mLineEditList [ Width_Edit ] - > setText ( Width ) ;
mLineEditList [ Height_Edit ] - > setText ( Height ) ;
if ( Update )
SettingsModified ( true ) ;
connect ( mLineEditList [ Height_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
connect ( mLineEditList [ Width_Edit ] , SIGNAL ( textChanged ( const QString & ) ) , this , SLOT ( SizeChanged ( const QString & ) ) ) ;
}
void lcBlenderPreferences : : ValidateColourScheme ( int Index )
{
QComboBox * ComboBox = qobject_cast < QComboBox * > ( sender ( ) ) ;
if ( ! ComboBox )
return ;
const bool ImportMM = mImportMMActBox - > isChecked ( ) ;
const int Color_Scheme = ImportMM ? int ( LBL_COLOUR_SCHEME_MM ) : int ( LBL_COLOUR_SCHEME ) ;
BlenderSettings * Settings = ImportMM ? mBlenderSettingsMM : mBlenderSettings ;
if ( ComboBox - > itemText ( Index ) = = " custom " & & mBlenderPaths [ PATH_LDCONFIG ] . value . isEmpty ( ) & & lcGetProfileString ( LC_PROFILE_COLOR_CONFIG ) . isEmpty ( ) )
{
BlenderSettings const * defaultSettings = ImportMM ? mDefaultSettingsMM : mDefaultSettings ;
Settings [ Color_Scheme ] . value = defaultSettings [ Color_Scheme ] . value ;
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " Custom LDraw Colours " ) ;
const QString & Header = " <b> " + tr ( " Colour scheme 'custom' cannot be enabled. Custom LDConfig file not found. " ) + " </b> " ;
const QString & Body = tr ( " Colour scheme 'custom' selected but no LDConfig file was specified.<br>The default colour scheme '%1' will be used.<br> " ) . arg ( Settings [ Color_Scheme ] . value ) ;
2023-06-02 00:20:49 +02:00
ShowMessage ( Header , Title , Body , QString ( ) , MBB_OK , QMessageBox : : Warning ) ;
}
else
{
bool Change = Settings [ Color_Scheme ] . value ! = ComboBox - > itemText ( Index ) ;
Change | = SettingsModified ( false ) ;
emit SettingChangedSig ( Change ) ;
}
}
bool lcBlenderPreferences : : PromptAccept ( )
{
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " Render Settings Modified " ) ;
const QString & Header = " <b> " + tr ( " Do you want to accept the modified settings before quitting ? " ) + " </b> " ;
2023-06-02 00:20:49 +02:00
int Exec = ShowMessage ( Header , Title , QString ( ) , QString ( ) , MBB_YES_NO , QMessageBox : : Question ) ;
if ( Exec = = QMessageBox : : Yes )
return true ;
return false ;
}
void lcBlenderPreferences : : LoadDefaultParameters ( QByteArray & Buffer , int Which )
{
/*
# File: BlenderLDrawParameters.lst
#
# This config file captures parameters for the Blender LDraw Render addon
# Parameters must be prefixed using one of the following predefined
# 'Item' labels:
# - lgeo_colour
# - sloped_brick
# - light_brick
# LGEO CUSTOM COLOURS
# LGEO is a parts library for rendering LEGO using the POV-Ray
# rendering software. This is the list of LEGO colours suitable
# for realistic rendering extracted from the LGEO file 'lg_color.inc'.
# When the 'Colour Scheme' option is set to 'Realistic', the standard
# LDraw colours RGB value is overwritten with the values defined here.
# Note: You can customize these RGB values as you want.
# Item------- ID-- R-- G-- B--
*/
const char DefaultCustomColours [ ] =
{
" lgeo_colour, 0, 33, 33, 33 \n "
" lgeo_colour, 1, 13, 105, 171 \n "
" lgeo_colour, 2, 40, 127, 70 \n "
" lgeo_colour, 3, 0, 143, 155 \n "
" lgeo_colour, 4, 196, 40, 27 \n "
" lgeo_colour, 5, 205, 98, 152 \n "
" lgeo_colour, 6, 98, 71, 50 \n "
" lgeo_colour, 7, 161, 165, 162 \n "
" lgeo_colour, 8, 109, 110, 108 \n "
" lgeo_colour, 9, 180, 210, 227 \n "
" lgeo_colour, 10, 75, 151, 74 \n "
" lgeo_colour, 11, 85, 165, 175 \n "
" lgeo_colour, 12, 242, 112, 94 \n "
" lgeo_colour, 13, 252, 151, 172 \n "
" lgeo_colour, 14, 245, 205, 47 \n "
" lgeo_colour, 15, 242, 243, 242 \n "
" lgeo_colour, 17, 194, 218, 184 \n "
" lgeo_colour, 18, 249, 233, 153 \n "
" lgeo_colour, 19, 215, 197, 153 \n "
" lgeo_colour, 20, 193, 202, 222 \n "
" lgeo_colour, 21, 224, 255, 176 \n "
" lgeo_colour, 22, 107, 50, 123 \n "
" lgeo_colour, 23, 35, 71, 139 \n "
" lgeo_colour, 25, 218, 133, 64 \n "
" lgeo_colour, 26, 146, 57, 120 \n "
" lgeo_colour, 27, 164, 189, 70 \n "
" lgeo_colour, 28, 149, 138, 115 \n "
" lgeo_colour, 29, 228, 173, 200 \n "
" lgeo_colour, 30, 172, 120, 186 \n "
" lgeo_colour, 31, 225, 213, 237 \n "
" lgeo_colour, 32, 0, 20, 20 \n "
" lgeo_colour, 33, 123, 182, 232 \n "
" lgeo_colour, 34, 132, 182, 141 \n "
" lgeo_colour, 35, 217, 228, 167 \n "
" lgeo_colour, 36, 205, 84, 75 \n "
" lgeo_colour, 37, 228, 173, 200 \n "
" lgeo_colour, 38, 255, 43, 0 \n "
" lgeo_colour, 40, 166, 145, 130 \n "
" lgeo_colour, 41, 170, 229, 255 \n "
" lgeo_colour, 42, 198, 255, 0 \n "
" lgeo_colour, 43, 193, 223, 240 \n "
" lgeo_colour, 44, 150, 112, 159 \n "
" lgeo_colour, 46, 247, 241, 141 \n "
" lgeo_colour, 47, 252, 252, 252 \n "
" lgeo_colour, 52, 156, 149, 199 \n "
" lgeo_colour, 54, 255, 246, 123 \n "
" lgeo_colour, 57, 226, 176, 96 \n "
" lgeo_colour, 65, 236, 201, 53 \n "
" lgeo_colour, 66, 202, 176, 0 \n "
" lgeo_colour, 67, 255, 255, 255 \n "
" lgeo_colour, 68, 243, 207, 155 \n "
" lgeo_colour, 69, 142, 66, 133 \n "
" lgeo_colour, 70, 105, 64, 39 \n "
" lgeo_colour, 71, 163, 162, 164 \n "
" lgeo_colour, 72, 99, 95, 97 \n "
" lgeo_colour, 73, 110, 153, 201 \n "
" lgeo_colour, 74, 161, 196, 139 \n "
" lgeo_colour, 77, 220, 144, 149 \n "
" lgeo_colour, 78, 246, 215, 179 \n "
" lgeo_colour, 79, 255, 255, 255 \n "
" lgeo_colour, 80, 140, 140, 140 \n "
" lgeo_colour, 82, 219, 172, 52 \n "
" lgeo_colour, 84, 170, 125, 85 \n "
" lgeo_colour, 85, 52, 43, 117 \n "
" lgeo_colour, 86, 124, 92, 69 \n "
" lgeo_colour, 89, 155, 178, 239 \n "
" lgeo_colour, 92, 204, 142, 104 \n "
" lgeo_colour, 100, 238, 196, 182 \n "
" lgeo_colour, 115, 199, 210, 60 \n "
" lgeo_colour, 134, 174, 122, 89 \n "
" lgeo_colour, 135, 171, 173, 172 \n "
" lgeo_colour, 137, 106, 122, 150 \n "
" lgeo_colour, 142, 220, 188, 129 \n "
" lgeo_colour, 148, 62, 60, 57 \n "
" lgeo_colour, 151, 14, 94, 77 \n "
" lgeo_colour, 179, 160, 160, 160 \n "
" lgeo_colour, 183, 242, 243, 242 \n "
" lgeo_colour, 191, 248, 187, 61 \n "
" lgeo_colour, 212, 159, 195, 233 \n "
" lgeo_colour, 216, 143, 76, 42 \n "
" lgeo_colour, 226, 253, 234, 140 \n "
" lgeo_colour, 232, 125, 187, 221 \n "
" lgeo_colour, 256, 33, 33, 33 \n "
" lgeo_colour, 272, 32, 58, 86 \n "
" lgeo_colour, 273, 13, 105, 171 \n "
" lgeo_colour, 288, 39, 70, 44 \n "
" lgeo_colour, 294, 189, 198, 173 \n "
" lgeo_colour, 297, 170, 127, 46 \n "
" lgeo_colour, 308, 53, 33, 0 \n "
" lgeo_colour, 313, 171, 217, 255 \n "
" lgeo_colour, 320, 123, 46, 47 \n "
" lgeo_colour, 321, 70, 155, 195 \n "
" lgeo_colour, 322, 104, 195, 226 \n "
" lgeo_colour, 323, 211, 242, 234 \n "
" lgeo_colour, 324, 196, 0, 38 \n "
" lgeo_colour, 326, 226, 249, 154 \n "
" lgeo_colour, 330, 119, 119, 78 \n "
" lgeo_colour, 334, 187, 165, 61 \n "
" lgeo_colour, 335, 149, 121, 118 \n "
" lgeo_colour, 366, 209, 131, 4 \n "
" lgeo_colour, 373, 135, 124, 144 \n "
" lgeo_colour, 375, 193, 194, 193 \n "
" lgeo_colour, 378, 120, 144, 129 \n "
" lgeo_colour, 379, 94, 116, 140 \n "
" lgeo_colour, 383, 224, 224, 224 \n "
" lgeo_colour, 406, 0, 29, 104 \n "
" lgeo_colour, 449, 129, 0, 123 \n "
" lgeo_colour, 450, 203, 132, 66 \n "
" lgeo_colour, 462, 226, 155, 63 \n "
" lgeo_colour, 484, 160, 95, 52 \n "
" lgeo_colour, 490, 215, 240, 0 \n "
" lgeo_colour, 493, 101, 103, 97 \n "
" lgeo_colour, 494, 208, 208, 208 \n "
" lgeo_colour, 496, 163, 162, 164 \n "
" lgeo_colour, 503, 199, 193, 183 \n "
" lgeo_colour, 504, 137, 135, 136 \n "
" lgeo_colour, 511, 250, 250, 250 \n "
} ;
/*
# SLOPED BRICKS
# Dictionary with part number (without any extension for decorations), as key,
# of pieces that have grainy slopes, and, as values, a set containing the angles (in
# degrees) of the face's normal to the horizontal plane. Use a | delimited tuple to
# represent a range within which the angle must lie.
# Item-------- PartID- Angle / Angle Range (in degrees)
*/
const char DefaultSlopedBricks [ ] =
{
" sloped_brick, 962, 45 \n "
" sloped_brick, 2341, -45 \n "
" sloped_brick, 2449, -16 \n "
" sloped_brick, 2875, 45 \n "
" sloped_brick, 2876, 40|63 \n "
" sloped_brick, 3037, 45 \n "
" sloped_brick, 3038, 45 \n "
" sloped_brick, 3039, 45 \n "
" sloped_brick, 3040, 45 \n "
" sloped_brick, 3041, 45 \n "
" sloped_brick, 3042, 45 \n "
" sloped_brick, 3043, 45 \n "
" sloped_brick, 3044, 45 \n "
" sloped_brick, 3045, 45 \n "
" sloped_brick, 3046, 45 \n "
" sloped_brick, 3048, 45 \n "
" sloped_brick, 3049, 45 \n "
" sloped_brick, 3135, 45 \n "
" sloped_brick, 3297, 63 \n "
" sloped_brick, 3298, 63 \n "
" sloped_brick, 3299, 63 \n "
" sloped_brick, 3300, 63 \n "
" sloped_brick, 3660, -45 \n "
" sloped_brick, 3665, -45 \n "
" sloped_brick, 3675, 63 \n "
" sloped_brick, 3676, -45 \n "
" sloped_brick, 3678b, 24 \n "
" sloped_brick, 3684, 15 \n "
" sloped_brick, 3685, 16 \n "
" sloped_brick, 3688, 15 \n "
" sloped_brick, 3747, -63 \n "
" sloped_brick, 4089, -63 \n "
" sloped_brick, 4161, 63 \n "
" sloped_brick, 4286, 63 \n "
" sloped_brick, 4287, -63 \n "
" sloped_brick, 4445, 45 \n "
" sloped_brick, 4460, 16 \n "
" sloped_brick, 4509, 63 \n "
" sloped_brick, 4854, -45 \n "
" sloped_brick, 4856, -60|-70, -45 \n "
" sloped_brick, 4857, 45 \n "
" sloped_brick, 4858, 72 \n "
" sloped_brick, 4861, 45, 63 \n "
" sloped_brick, 4871, -45 \n "
" sloped_brick, 4885, 72 \n "
" sloped_brick, 6069, 72, 45 \n "
" sloped_brick, 6153, 60|70, 26|4 \n "
" sloped_brick, 6227, 45 \n "
" sloped_brick, 6270, 45 \n "
" sloped_brick, 13269, 40|63 \n "
" sloped_brick, 13548, 45 \n "
" sloped_brick, 15571, 45 \n "
" sloped_brick, 18759, -45 \n "
" sloped_brick, 22390, 40|55 \n "
" sloped_brick, 22391, 40|55 \n "
" sloped_brick, 22889, -45 \n "
" sloped_brick, 28192, 45 \n "
" sloped_brick, 30180, 47 \n "
" sloped_brick, 30182, 45 \n "
" sloped_brick, 30183, -45 \n "
" sloped_brick, 30249, 35 \n "
" sloped_brick, 30283, -45 \n "
" sloped_brick, 30363, 72 \n "
" sloped_brick, 30373, -24 \n "
" sloped_brick, 30382, 11, 45 \n "
" sloped_brick, 30390, -45 \n "
" sloped_brick, 30499, 16 \n "
" sloped_brick, 32083, 45 \n "
" sloped_brick, 43708, 72 \n "
" sloped_brick, 43710, 72, 45 \n "
" sloped_brick, 43711, 72, 45 \n "
" sloped_brick, 47759, 40|63 \n "
" sloped_brick, 52501, -45 \n "
" sloped_brick, 60219, -45 \n "
" sloped_brick, 60477, 72 \n "
" sloped_brick, 60481, 24 \n "
" sloped_brick, 63341, 45 \n "
" sloped_brick, 72454, -45 \n "
" sloped_brick, 92946, 45 \n "
" sloped_brick, 93348, 72 \n "
" sloped_brick, 95188, 65 \n "
" sloped_brick, 99301, 63 \n "
" sloped_brick, 303923, 45 \n "
" sloped_brick, 303926, 45 \n "
" sloped_brick, 304826, 45 \n "
" sloped_brick, 329826, 64 \n "
" sloped_brick, 374726, -64 \n "
" sloped_brick, 428621, 64 \n "
" sloped_brick, 4162628, 17 \n "
" sloped_brick, 4195004, 45 \n "
} ;
/*
# LIGHTED BRICKS
# Dictionary with part number (with extension), as key,
# of lighted bricks, light emission colour and intensity, as values.
# Item--------- PartID--- Light-------------- Intensity
*/
const char DefaultLightedBricks [ ] =
{
" lighted_brick, 62930.dat, 1.000, 0.373, 0.059, 1.0 \n "
" lighted_brick, 54869.dat, 1.000, 0.052, 0.017, 1.0 \n "
} ;
Buffer . clear ( ) ;
if ( Which = = PARAMS_CUSTOM_COLOURS )
Buffer . append ( DefaultCustomColours , sizeof ( DefaultCustomColours ) ) ;
else if ( Which = = PARAMS_SLOPED_BRICKS )
Buffer . append ( DefaultSlopedBricks , sizeof ( DefaultSlopedBricks ) ) ;
else if ( Which = = PARAMS_LIGHTED_BRICKS )
Buffer . append ( DefaultLightedBricks , sizeof ( DefaultLightedBricks ) ) ;
}
bool lcBlenderPreferences : : ExportParameterFile ( )
{
2023-07-07 00:51:51 +02:00
const QString BlenderConfigDir = QString ( " %1/Blender/setup/addon_setup/config " ) . arg ( gAddonPreferences - > mDataDir ) ;
const QString ParameterFile = QString ( " %1/%2 " ) . arg ( BlenderConfigDir ) . arg ( LC_BLENDER_ADDON_PARAMS_FILE ) ;
2023-06-02 00:20:49 +02:00
QFile File ( ParameterFile ) ;
if ( ! OverwriteFile ( File . fileName ( ) ) )
return true ;
QString Message ;
if ( File . open ( QIODevice : : WriteOnly | QIODevice : : Text ) )
{
int Counter = 1 ;
QByteArray Buffer ;
QTextStream Stream ( & File ) ;
Stream < < " # File: " < < QFileInfo ( ParameterFile ) . fileName ( ) < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " # This config file captures parameters for the Blender LDraw Render addon " < < LineEnding ;
Stream < < " # Parameters must be prefixed using one of the following predefined " < < LineEnding ;
Stream < < " # 'Item' labels: " < < LineEnding ;
Stream < < " # - lgeo_colour " < < LineEnding ;
Stream < < " # - sloped_brick " < < LineEnding ;
Stream < < " # - light_brick " < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " # All items must use a comma',' delimiter as the primary delimiter. " < < LineEnding ;
Stream < < " # For sloped_brick items, a pipe'|' delimiter must be used to specify " < < LineEnding ;
Stream < < " # a range (min|max) within which the angle must lie when appropriate. " < < LineEnding ;
Stream < < " # Spaces between item attributes are not required and are used to " < < LineEnding ;
Stream < < " # facilitate human readability. " < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " # LGEO CUSTOM COLOURS " < < LineEnding ;
Stream < < " # LGEO is a parts library for rendering LEGO using the POV-Ray " < < LineEnding ;
Stream < < " # rendering software. This is the list of LEGO colours suitable " < < LineEnding ;
Stream < < " # for realistic rendering extracted from the LGEO file 'lg_color.inc'. " < < LineEnding ;
Stream < < " # When the 'Colour Scheme' option is set to 'Realistic', the standard " < < LineEnding ;
Stream < < " # LDraw colours RGB value is overwritten with the values defined here. " < < LineEnding ;
Stream < < " # Note: You can customize these RGB values as you want. " < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " # Item----- ID- R-- G-- B-- " < < LineEnding ;
LoadDefaultParameters ( Buffer , PARAMS_CUSTOM_COLOURS ) ;
QTextStream colourstream ( Buffer ) ;
for ( QString Line = colourstream . readLine ( ) ; ! Line . isNull ( ) ; Line = colourstream . readLine ( ) )
{
Stream < < Line < < LineEnding ;
Counter + + ;
}
Stream < < " " < < LineEnding ;
Stream < < " # SLOPED BRICKS " < < LineEnding ;
Stream < < " # Dictionary with part number (without any extension for decorations), as key, " < < LineEnding ;
Stream < < " # of pieces that have grainy slopes, and, as values, a set containing the angles (in " < < LineEnding ;
Stream < < " # degrees) of the face's normal to the horizontal plane. Use a | delimited tuple to " < < LineEnding ;
Stream < < " # represent a range within which the angle must lie. " < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " # Item------ PartID- Angle/Angle Range (in degrees) " < < LineEnding ;
LoadDefaultParameters ( Buffer , PARAMS_SLOPED_BRICKS ) ;
QTextStream SlopedStream ( Buffer ) ;
for ( QString Line = SlopedStream . readLine ( ) ; ! Line . isNull ( ) ; Line = SlopedStream . readLine ( ) )
{
Stream < < Line < < LineEnding ;
Counter + + ;
}
Stream < < " " < < LineEnding ;
Stream < < " # LIGHTED BRICKS " < < LineEnding ;
Stream < < " # Dictionary with part number (with extension), as key, " < < LineEnding ;
Stream < < " # of lighted bricks, light emission colour and intensity, as values. " < < LineEnding ;
Stream < < " " < < LineEnding ;
Stream < < " # Item------- PartID--- Light-------------- Intensity " < < LineEnding ;
LoadDefaultParameters ( Buffer , PARAMS_LIGHTED_BRICKS ) ;
QTextStream lightedstream ( Buffer ) ;
for ( QString Line = lightedstream . readLine ( ) ; ! Line . isNull ( ) ; Line = lightedstream . readLine ( ) )
{
Stream < < Line < < LineEnding ;
Counter + + ;
}
Stream < < " " < < LineEnding ;
Stream < < " # end of parameters " < < LineEnding ;
File . close ( ) ;
Message = tr ( " Finished writing Blender parameter entries. Processed %1 lines in file [%2]. " )
. arg ( Counter )
. arg ( File . fileName ( ) ) ;
}
else
{
Message = tr ( " Failed to open Blender parameter file: %1:<br>%2 " )
. arg ( File . fileName ( ) )
. arg ( File . errorString ( ) ) ;
ShowMessage ( Message ) ;
return false ;
}
return true ;
}
bool lcBlenderPreferences : : OverwriteFile ( const QString & File )
{
QFileInfo fileInfo ( File ) ;
if ( ! fileInfo . exists ( ) )
return true ;
2023-07-07 00:51:51 +02:00
const QString & Title = tr ( " Replace Existing File " ) ;
const QString Header = " <b> " + QMessageBox : : tr ( " Existing file %1 detected. " ) . arg ( fileInfo . fileName ( ) ) + " </b> " ;
const QString Body = QMessageBox : : tr ( " \" %1 \" <br>This file already exists.<br>Replace existing file? " ) . arg ( fileInfo . fileName ( ) ) ;
2023-06-02 00:20:49 +02:00
int Exec = ShowMessage ( Header , Title , Body , QString ( ) , MBB_YES , QMessageBox : : NoIcon ) ;
return ( Exec = = QMessageBox : : Yes ) ;
}
2023-07-07 00:51:51 +02:00
int lcBlenderPreferences : : ShowMessage ( const QString & Header , const QString & Title , const QString & Body , const QString & Detail , int const Buttons , int const Icon )
2023-06-02 00:20:49 +02:00
{
if ( ! gMainWindow )
return QMessageBox : : Ok ;
QMessageBox Box ;
Box . setWindowIcon ( QIcon ( ) ) ;
if ( ! Icon )
{
QPixmap Pixmap = QPixmap ( " :/resources/leocad.png " ) ;
Box . setIconPixmap ( Pixmap ) ;
}
else
Box . setIcon ( static_cast < QMessageBox : : Icon > ( Icon ) ) ;
Box . setTextFormat ( Qt : : RichText ) ;
Box . setWindowFlags ( Qt : : Dialog | Qt : : CustomizeWindowHint | Qt : : WindowTitleHint ) ;
if ( ! Title . isEmpty ( ) )
Box . setWindowTitle ( Title ) ;
else
Box . setWindowTitle ( tr ( " %1 Blender LDraw Addon " ) . arg ( LC_PRODUCTNAME_STR ) ) ;
Box . setText ( Header ) ;
if ( ! Body . isEmpty ( ) )
Box . setInformativeText ( Body ) ;
if ( ! Detail . isEmpty ( ) )
Box . setDetailedText ( QString ( Detail ) . replace ( " <br> " , " \n " ) ) ;
switch ( Buttons )
{
case MBB_YES :
Box . setStandardButtons ( QMessageBox : : Yes | QMessageBox : : Cancel ) ;
Box . setDefaultButton ( QMessageBox : : Yes ) ;
break ;
case MBB_YES_NO :
Box . setStandardButtons ( QMessageBox : : Yes | QMessageBox : : No | QMessageBox : : Cancel ) ;
Box . setDefaultButton ( QMessageBox : : Yes ) ;
break ;
default :
Box . setStandardButtons ( QMessageBox : : Ok ) ;
break ;
}
int MinimumWidth = 400 ;
int FontWidth = QFontMetrics ( Box . font ( ) ) . averageCharWidth ( ) ;
int FixedTextLength = ( MinimumWidth / FontWidth ) ;
if ( Header . length ( ) < Body . length ( ) & & Header . length ( ) < FixedTextLength )
{
QGridLayout * BoxLayout = ( QGridLayout * ) Box . layout ( ) ;
QLayoutItem * BoxLayoutItem = BoxLayout - > itemAtPosition ( 0 , 2 ) ;
QWidget * TextWidget = BoxLayoutItem - > widget ( ) ;
if ( TextWidget )
{
int FixedWidth = Body . length ( ) * FontWidth ;
if ( FixedWidth = = MinimumWidth )
{
int Index = ( MinimumWidth / FontWidth ) - 1 ;
2024-04-28 02:19:34 +02:00
if ( ! Body . mid ( Index , 1 ) . isEmpty ( ) )
2023-06-02 00:20:49 +02:00
FixedWidth = Body . indexOf ( " " , Index ) ;
}
else if ( FixedWidth < MinimumWidth )
FixedWidth = MinimumWidth ;
TextWidget - > setFixedWidth ( FixedWidth ) ;
}
}
2023-07-30 11:43:13 +02:00
const bool DownloadRequest = Body . startsWith ( tr ( " Do you want to download version " ) ) ;
if ( DownloadRequest ) {
QCheckBox * AddonVersionCheck = new QCheckBox ( tr ( " Do not show download new addon version message again. " ) ) ;
Box . setCheckBox ( AddonVersionCheck ) ;
QObject : : connect ( AddonVersionCheck , & QCheckBox : : stateChanged , [ ] ( int State )
{
bool VersionCheck = true ;
if ( static_cast < Qt : : CheckState > ( State ) = = Qt : : CheckState : : Checked )
VersionCheck = false ;
lcSetProfileInt ( LC_PROFILE_BLENDER_ADDON_VERSION_CHECK , ( int ) VersionCheck ) ;
} ) ;
}
2023-06-02 00:20:49 +02:00
return Box . exec ( ) ;
}
2023-05-26 16:17:16 +02:00
void lcBlenderPreferences : : DownloadFinished ( lcHttpReply * Reply )
2023-06-02 00:20:49 +02:00
{
2023-05-26 16:17:16 +02:00
if ( ! Reply - > error ( ) )
mData = Reply - > readAll ( ) ;
2023-06-02 00:20:49 +02:00
else
2023-05-26 16:17:16 +02:00
ShowMessage ( tr ( " Addon download failed. " ) ) ;
2023-06-02 00:20:49 +02:00
mHttpReply = nullptr ;
2023-05-26 16:17:16 +02:00
Reply - > deleteLater ( ) ;
2023-06-02 00:20:49 +02:00
}
2023-05-26 16:17:59 +02:00
namespace WindowsFileAttributes
{
enum
{
Dir = 0x10 , // FILE_ATTRIBUTE_DIRECTORY
File = 0x80 , // FILE_ATTRIBUTE_NORMAL
TypeMask = 0x90 ,
ReadOnly = 0x01 , // FILE_ATTRIBUTE_READONLY
PermMask = 0x01
} ;
}
namespace UnixFileAttributes
{
enum
{
Dir = 0040000 , // __S_IFDIR
File = 0100000 , // __S_IFREG
SymLink = 0120000 , // __S_IFLNK
TypeMask = 0170000 , // __S_IFMT
ReadUser = 0400 , // __S_IRUSR
WriteUser = 0200 , // __S_IWUSR
ExeUser = 0100 , // __S_IXUSR
ReadGroup = 0040 , // __S_IRGRP
WriteGroup = 0020 , // __S_IWGRP
ExeGroup = 0010 , // __S_IXGRP
ReadOther = 0004 , // __S_IROTH
WriteOther = 0002 , // __S_IWOTH
ExeOther = 0001 , // __S_IXOTH
PermMask = 0777
} ;
}
bool lcBlenderPreferences : : ExtractAddon ( const QString FileName , QString & Result )
{
enum ZipHostOS
{
HostFAT = 0 ,
HostUnix = 3 ,
HostHPFS = 6 , // filesystem used by OS/2 (and NT 3.x)
HostNTFS = 11 , // filesystem used by Windows NT
HostVFAT = 14 , // filesystem used by Windows 95, NT
HostOSX = 19
} ;
struct ZipFileInfo
{
ZipFileInfo ( lcZipFileInfo & FileInfo ) noexcept
: ZipInfo ( FileInfo ) , isDir ( false ) , isFile ( false ) , isSymLink ( false )
{
}
bool IsValid ( ) const noexcept { return isDir | | isFile | | isSymLink ; }
lcZipFileInfo & ZipInfo ;
QString filePath ;
uint isDir : 1 ;
uint isFile : 1 ;
uint isSymLink : 1 ;
QFile : : Permissions permissions ;
} ;
auto ModeToPermissions = [ ] ( quint32 Mode )
{
QFile : : Permissions Permissions ;
if ( Mode & UnixFileAttributes : : ReadUser )
Permissions | = QFile : : ReadOwner | QFile : : ReadUser ;
if ( Mode & UnixFileAttributes : : WriteUser )
Permissions | = QFile : : WriteOwner | QFile : : WriteUser ;
if ( Mode & UnixFileAttributes : : ExeUser )
Permissions | = QFile : : ExeOwner | QFile : : ExeUser ;
if ( Mode & UnixFileAttributes : : ReadGroup )
Permissions | = QFile : : ReadGroup ;
if ( Mode & UnixFileAttributes : : WriteGroup )
Permissions | = QFile : : WriteGroup ;
if ( Mode & UnixFileAttributes : : ExeGroup )
Permissions | = QFile : : ExeGroup ;
if ( Mode & UnixFileAttributes : : ReadOther )
Permissions | = QFile : : ReadOther ;
if ( Mode & UnixFileAttributes : : WriteOther )
Permissions | = QFile : : WriteOther ;
if ( Mode & UnixFileAttributes : : ExeOther )
Permissions | = QFile : : ExeOther ;
return Permissions ;
} ;
lcZipFile ZipFile ;
if ( ! ZipFile . OpenRead ( FileName ) )
return false ;
2023-07-07 00:51:51 +02:00
const QString DestinationDir = QFileInfo ( FileName ) . absolutePath ( ) ;
2023-05-26 16:17:59 +02:00
bool Ok = true ;
int Extracted = 0 ;
2024-05-14 04:59:37 +02:00
for ( quint32 FileIdx = 0 ; FileIdx < ZipFile . mFiles . size ( ) ; FileIdx + + )
2023-05-26 16:17:59 +02:00
{
ZipFileInfo FileInfo ( ZipFile . mFiles [ FileIdx ] ) ;
quint32 Mode = FileInfo . ZipInfo . external_fa ;
const ZipHostOS HostOS = ZipHostOS ( FileInfo . ZipInfo . version > > 8 ) ;
switch ( HostOS )
{
case HostOSX :
case HostUnix :
Mode = ( Mode > > 16 ) & 0xffff ;
switch ( Mode & UnixFileAttributes : : TypeMask )
{
case UnixFileAttributes : : SymLink :
FileInfo . isSymLink = true ;
break ;
case UnixFileAttributes : : Dir :
FileInfo . isDir = true ;
break ;
case UnixFileAttributes : : File :
default :
FileInfo . isFile = true ;
break ;
}
FileInfo . permissions = ModeToPermissions ( Mode ) ;
break ;
case HostFAT :
case HostNTFS :
case HostHPFS :
case HostVFAT :
switch ( Mode & WindowsFileAttributes : : TypeMask )
{
case WindowsFileAttributes : : Dir :
FileInfo . isDir = true ;
break ;
case WindowsFileAttributes : : File :
default :
FileInfo . isFile = true ;
break ;
}
FileInfo . permissions | = QFile : : ReadOwner | QFile : : ReadUser | QFile : : ReadGroup | QFile : : ReadOther ;
if ( ( Mode & WindowsFileAttributes : : ReadOnly ) = = 0 )
FileInfo . permissions | = QFile : : WriteOwner | QFile : : WriteUser | QFile : : WriteGroup | QFile : : WriteOther ;
if ( FileInfo . isDir )
FileInfo . permissions | = QFile : : ExeOwner | QFile : : ExeUser | QFile : : ExeGroup | QFile : : ExeOther ;
break ;
default :
2023-07-07 00:51:51 +02:00
ShowMessage ( tr ( " ZipFile entry format (HostOS %1) at index %2 is not supported. Extract terminated. " ) . arg ( HostOS ) . arg ( FileIdx ) , tr ( " Extract Addon " ) , QString ( ) , QString ( ) , MBB_OK , QMessageBox : : Warning ) ;
2023-05-26 16:17:59 +02:00
Ok = false ;
}
if ( ! Ok | | ! ( Ok = FileInfo . IsValid ( ) ) )
break ;
// Check the file path - if broken, convert separators, eat leading and trailing ones
FileInfo . filePath = QDir : : fromNativeSeparators ( FileInfo . ZipInfo . file_name ) ;
2024-04-28 02:19:34 +02:00
QString FilePathRef ( FileInfo . filePath ) ;
2023-05-26 16:17:59 +02:00
while ( FilePathRef . startsWith ( QLatin1Char ( ' . ' ) ) | | FilePathRef . startsWith ( QLatin1Char ( ' / ' ) ) )
FilePathRef = FilePathRef . mid ( 1 ) ;
while ( FilePathRef . endsWith ( QLatin1Char ( ' / ' ) ) )
FilePathRef . chop ( 1 ) ;
2024-04-28 02:19:34 +02:00
FileInfo . filePath = FilePathRef ;
2023-05-26 16:17:59 +02:00
2023-07-07 00:51:51 +02:00
const QString AbsPath = QDir : : fromNativeSeparators ( DestinationDir + QDir : : separator ( ) + FileInfo . filePath ) ;
2023-05-26 16:17:59 +02:00
// directories
if ( FileInfo . isDir )
{
QDir BaseDir ( DestinationDir ) ;
if ( ! ( Ok = BaseDir . mkpath ( FileInfo . filePath ) ) )
break ;
if ( ! ( Ok = QFile : : setPermissions ( AbsPath , FileInfo . permissions ) ) )
break ;
Extracted + + ;
continue ;
}
lcMemFile MemFile ;
ZipFile . ExtractFile ( FileIdx , MemFile ) ;
2023-06-19 03:04:08 +02:00
QByteArray const & ByteArray = QByteArray : : fromRawData ( ( const char * ) MemFile . mBuffer , ( int ) MemFile . GetLength ( ) ) ;
2023-05-26 16:17:59 +02:00
// symlinks
if ( FileInfo . isSymLink )
{
QString Destination = QFile : : decodeName ( ByteArray ) ;
if ( ! ( Ok = ! Destination . isEmpty ( ) ) )
break ;
QFileInfo LinkFileInfo ( AbsPath ) ;
if ( ! QFile : : exists ( LinkFileInfo . absolutePath ( ) ) )
QDir : : root ( ) . mkpath ( LinkFileInfo . absolutePath ( ) ) ;
if ( ! ( Ok = QFile : : link ( Destination , AbsPath ) ) )
break ;
Extracted + + ;
continue ;
}
// files
if ( FileInfo . isFile )
{
QFile File ( AbsPath ) ;
if ( ! ( Ok = File . open ( QIODevice : : WriteOnly ) ) )
break ;
File . write ( ByteArray ) ;
File . setPermissions ( FileInfo . permissions ) ;
File . close ( ) ;
Extracted + + ;
}
}
if ( ! Ok )
2024-05-14 04:59:37 +02:00
Result = tr ( " %1 of %2 files extracted. " ) . arg ( Extracted ) . arg ( ZipFile . mFiles . size ( ) ) ;
2023-05-26 16:17:59 +02:00
return Ok ;
}