Merge remote-tracking branch 'origin/master' into ys_msw_dpi
							
								
								
									
										309
									
								
								README.md
									
										
									
									
									
								
							
							
						
						|  | @ -20,9 +20,8 @@ All user facing code is written in C++, and some legacy code as well as unit | |||
| tests are written in Perl. Perl is not required for either development or use | ||||
| of Slic3r. | ||||
| 
 | ||||
| The C++ API is public and its use in other projects is encouraged. | ||||
| The goal is to make Slic3r fully modular so that any part of its logic | ||||
| can be used separately. | ||||
| The slicing core is the `libslic3r` library, which can be built and used in a standalone way. | ||||
| The command line interface is a thin wrapper over `libslic3r`. | ||||
| 
 | ||||
| ### What are Slic3r's main features? | ||||
| 
 | ||||
|  | @ -67,309 +66,13 @@ Sure! You can do the following to find things that are available to help with: | |||
| 
 | ||||
| ### What's Slic3r license? | ||||
| 
 | ||||
| Slic3r is licensed under the _GNU Affero General Public License, version 3_. | ||||
| The author is Alessandro Ranellucci. | ||||
| Slic3r PE is licensed under the _GNU Affero General Public License, version 3_. | ||||
| The Prusa Edition is originally based on Slic3r by Alessandro Ranellucci. | ||||
| 
 | ||||
| The [Silk icon set](http://www.famfamfam.com/lab/icons/silk/) used in Slic3r is | ||||
| licensed under the _Creative Commons Attribution 3.0 License_. | ||||
| The author of the Silk icon set is Mark James. | ||||
| 
 | ||||
| ### How can I invoke slic3r.pl using the command line? | ||||
| ### How can I use Slic3r PE from the command line? | ||||
| 
 | ||||
|     Usage: slic3r.pl [ OPTIONS ] [ file.stl ] [ file2.stl ] ... | ||||
|      | ||||
|         --help              Output this usage screen and exit | ||||
|         --version           Output the version of Slic3r and exit | ||||
|         --save <file>       Save configuration to the specified file | ||||
|         --load <file>       Load configuration from the specified file. It can be used | ||||
|                             more than once to load options from multiple files. | ||||
|         -o, --output <file> File to output gcode to (by default, the file will be saved | ||||
|                             into the same directory as the input file using the | ||||
|                             --output-filename-format to generate the filename.) If a | ||||
|                             directory is specified for this option, the output will | ||||
|                             be saved under that directory, and the filename will be | ||||
|                             generated by --output-filename-format. | ||||
| 
 | ||||
|       Non-slicing actions (no G-code will be generated): | ||||
|         --repair            Repair given STL files and save them as <name>_fixed.obj | ||||
|         --cut <z>           Cut given input files at given Z (relative) and export | ||||
|                             them as <name>_upper.stl and <name>_lower.stl | ||||
|         --split             Split the shells contained in given STL file into several STL files | ||||
|         --info              Output information about the supplied file(s) and exit | ||||
|      | ||||
|         -j, --threads <num> Number of threads to use (1+, default: 2) | ||||
|      | ||||
|       GUI options: | ||||
|         --gui               Forces the GUI launch instead of command line slicing (if you | ||||
|                             supply a model file, it will be loaded into the plater) | ||||
|         --no-plater         Disable the plater tab | ||||
|         --no-gui            Forces the command line slicing instead of gui.  | ||||
|                             This takes precedence over --gui if both are present. | ||||
|         --autosave <file>   Automatically export current configuration to the specified file | ||||
|      | ||||
|       Output options: | ||||
|         --output-filename-format | ||||
|                             Output file name format; all config options enclosed in brackets | ||||
|                             will be replaced by their values, as well as [input_filename_base] | ||||
|                             and [input_filename] (default: [input_filename_base].gcode) | ||||
|         --post-process      Generated G-code will be processed with the supplied script; | ||||
|                             call this more than once to process through multiple scripts. | ||||
|         --export-png        Export zipped PNG files containing slices instead of G-code. | ||||
|         -m, --merge         If multiple files are supplied, they will be composed into a single | ||||
|                             print rather than processed individually. | ||||
|      | ||||
|       Printer options: | ||||
|         --nozzle-diameter   Diameter of nozzle in mm (default: 0.5) | ||||
|         --print-center      Coordinates in mm of the point to center the print around | ||||
|                             (default: 100,100) | ||||
|         --z-offset          Additional height in mm to add to vertical coordinates | ||||
|                             (+/-, default: 0) | ||||
|         --gcode-flavor      The type of G-code to generate (reprap/teacup/repetier/makerware/sailfish/mach3/machinekit/smoothie/no-extrusion, | ||||
|                             default: reprap) | ||||
|         --use-relative-e-distances Enable this to get relative E values (default: no) | ||||
|         --use-firmware-retraction  Enable firmware-controlled retraction using G10/G11 (default: no) | ||||
|         --use-volumetric-e  Express E in cubic millimeters and prepend M200 (default: no) | ||||
|         --gcode-comments    Make G-code verbose by adding comments (default: no) | ||||
|      | ||||
|       Filament options: | ||||
|         --filament-diameter Diameter in mm of your raw filament (default: 3) | ||||
|         --extrusion-multiplier | ||||
|                             Change this to alter the amount of plastic extruded. There should be | ||||
|                             very little need to change this value, which is only useful to | ||||
|                             compensate for filament packing (default: 1) | ||||
|         --temperature       Extrusion temperature in degree Celsius, set 0 to disable (default: 200) | ||||
|         --first-layer-temperature Extrusion temperature for the first layer, in degree Celsius, | ||||
|                             set 0 to disable (default: same as --temperature) | ||||
|         --bed-temperature   Heated bed temperature in degree Celsius, set 0 to disable (default: 0) | ||||
|         --first-layer-bed-temperature Heated bed temperature for the first layer, in degree Celsius, | ||||
|                             set 0 to disable (default: same as --bed-temperature) | ||||
|      | ||||
|       Speed options: | ||||
|         --travel-speed      Speed of non-print moves in mm/s (default: 130) | ||||
|         --perimeter-speed   Speed of print moves for perimeters in mm/s (default: 30) | ||||
|         --small-perimeter-speed | ||||
|                             Speed of print moves for small perimeters in mm/s or % over perimeter speed | ||||
|                             (default: 30) | ||||
|         --external-perimeter-speed | ||||
|                             Speed of print moves for the external perimeter in mm/s or % over perimeter speed | ||||
|                             (default: 70%) | ||||
|         --infill-speed      Speed of print moves in mm/s (default: 60) | ||||
|         --solid-infill-speed Speed of print moves for solid surfaces in mm/s or % over infill speed | ||||
|                             (default: 60) | ||||
|         --top-solid-infill-speed Speed of print moves for top surfaces in mm/s or % over solid infill speed | ||||
|                             (default: 50) | ||||
|         --support-material-speed | ||||
|                             Speed of support material print moves in mm/s (default: 60) | ||||
|         --support-material-interface-speed | ||||
|                             Speed of support material interface print moves in mm/s or % over support material | ||||
|                             speed (default: 100%) | ||||
|         --bridge-speed      Speed of bridge print moves in mm/s (default: 60) | ||||
|         --gap-fill-speed    Speed of gap fill print moves in mm/s (default: 20) | ||||
|         --first-layer-speed Speed of print moves for bottom layer, expressed either as an absolute | ||||
|                             value or as a percentage over normal speeds (default: 30%) | ||||
|      | ||||
|       Acceleration options: | ||||
|         --perimeter-acceleration | ||||
|                             Overrides firmware's default acceleration for perimeters. (mm/s^2, set zero | ||||
|                             to disable; default: 0) | ||||
|         --infill-acceleration | ||||
|                             Overrides firmware's default acceleration for infill. (mm/s^2, set zero | ||||
|                             to disable; default: 0) | ||||
|         --bridge-acceleration | ||||
|                             Overrides firmware's default acceleration for bridges. (mm/s^2, set zero | ||||
|                             to disable; default: 0) | ||||
|         --first-layer-acceleration | ||||
|                             Overrides firmware's default acceleration for first layer. (mm/s^2, set zero | ||||
|                             to disable; default: 0) | ||||
|         --default-acceleration | ||||
|                             Acceleration will be reset to this value after the specific settings above | ||||
|                             have been applied. (mm/s^2, set zero to disable; default: 0) | ||||
|      | ||||
|       Accuracy options: | ||||
|         --layer-height      Layer height in mm (default: 0.3) | ||||
|         --first-layer-height Layer height for first layer (mm or %, default: 0.35) | ||||
|         --infill-every-layers | ||||
|                             Infill every N layers (default: 1) | ||||
|         --solid-infill-every-layers | ||||
|                             Force a solid layer every N layers (default: 0) | ||||
|      | ||||
|       Print options: | ||||
|         --perimeters        Number of perimeters/horizontal skins (range: 0+, default: 3) | ||||
|         --top-solid-layers  Number of solid layers to do for top surfaces (range: 0+, default: 3) | ||||
|         --bottom-solid-layers  Number of solid layers to do for bottom surfaces (range: 0+, default: 3) | ||||
|         --solid-layers      Shortcut for setting the two options above at once | ||||
|         --fill-density      Infill density (range: 0%-100%, default: 40%) | ||||
|         --fill-angle        Infill angle in degrees (range: 0-90, default: 45) | ||||
|         --fill-pattern      Pattern to use to fill non-solid layers (default: honeycomb) | ||||
|         --solid-fill-pattern Pattern to use to fill solid layers (default: rectilinear) | ||||
|         --start-gcode       Load initial G-code from the supplied file. This will overwrite | ||||
|                             the default command (home all axes [G28]). | ||||
|         --end-gcode         Load final G-code from the supplied file. This will overwrite | ||||
|                             the default commands (turn off temperature [M104 S0], | ||||
|                             home X axis [G28 X], disable motors [M84]). | ||||
|         --before-layer-gcode  Load before-layer-change G-code from the supplied file (default: nothing). | ||||
|         --layer-gcode       Load after-layer-change G-code from the supplied file (default: nothing). | ||||
|         --toolchange-gcode  Load tool-change G-code from the supplied file (default: nothing). | ||||
|         --seam-position     Position of loop starting points (random/nearest/aligned, default: aligned). | ||||
|         --external-perimeters-first Reverse perimeter order. (default: no) | ||||
|         --spiral-vase       Experimental option to raise Z gradually when printing single-walled vases | ||||
|                             (default: no) | ||||
|         --only-retract-when-crossing-perimeters | ||||
|                             Disable retraction when travelling between infill paths inside the same island. | ||||
|                             (default: no) | ||||
|         --solid-infill-below-area | ||||
|                             Force solid infill when a region has a smaller area than this threshold | ||||
|                             (mm^2, default: 70) | ||||
|         --infill-only-where-needed | ||||
|                             Only infill under ceilings (default: no) | ||||
|         --infill-first      Make infill before perimeters (default: no) | ||||
|      | ||||
|        Quality options (slower slicing): | ||||
|         --extra-perimeters  Add more perimeters when needed (default: yes) | ||||
|         --avoid-crossing-perimeters Optimize travel moves so that no perimeters are crossed (default: no) | ||||
|         --thin-walls        Detect single-width walls (default: yes) | ||||
|         --overhangs         Experimental option to use bridge flow, speed and fan for overhangs | ||||
|                             (default: yes) | ||||
|      | ||||
|        Support material options: | ||||
|         --support-material  Generate support material for overhangs | ||||
|         --support-material-threshold | ||||
|                             Overhang threshold angle (range: 0-90, set 0 for automatic detection, | ||||
|                             default: 0) | ||||
|         --support-material-pattern | ||||
|                             Pattern to use for support material (default: honeycomb) | ||||
|         --support-material-spacing | ||||
|                             Spacing between pattern lines (mm, default: 2.5) | ||||
|         --support-material-angle | ||||
|                             Support material angle in degrees (range: 0-90, default: 0) | ||||
|         --support-material-contact-distance | ||||
|                             Vertical distance between object and support material | ||||
|                             (0+, default: 0.2) | ||||
|         --support-material-interface-layers | ||||
|                             Number of perpendicular layers between support material and object (0+, default: 3) | ||||
|         --support-material-interface-spacing | ||||
|                             Spacing between interface pattern lines (mm, set 0 to get a solid layer, default: 0) | ||||
|         --raft-layers       Number of layers to raise the printed objects by (range: 0+, default: 0) | ||||
|         --support-material-enforce-layers | ||||
|                             Enforce support material on the specified number of layers from bottom, | ||||
|                             regardless of --support-material and threshold (0+, default: 0) | ||||
|         --dont-support-bridges | ||||
|                             Experimental option for preventing support material from being generated under bridged areas (default: yes) | ||||
|      | ||||
|        Retraction options: | ||||
|         --retract-length    Length of retraction in mm when pausing extrusion (default: 1) | ||||
|         --retract-speed     Speed for retraction in mm/s (default: 30) | ||||
|         --retract-restart-extra | ||||
|                             Additional amount of filament in mm to push after | ||||
|                             compensating retraction (default: 0) | ||||
|         --retract-before-travel | ||||
|                             Only retract before travel moves of this length in mm (default: 2) | ||||
|         --retract-lift      Lift Z by the given distance in mm when retracting (default: 0) | ||||
|         --retract-lift-above Only lift Z when above the specified height (default: 0) | ||||
|         --retract-lift-below Only lift Z when below the specified height (default: 0) | ||||
|         --retract-layer-change | ||||
|                             Enforce a retraction before each Z move (default: no) | ||||
|         --wipe              Wipe the nozzle while doing a retraction (default: no) | ||||
|      | ||||
|        Retraction options for multi-extruder setups: | ||||
|         --retract-length-toolchange | ||||
|                             Length of retraction in mm when disabling tool (default: 10) | ||||
|         --retract-restart-extra-toolchange | ||||
|                             Additional amount of filament in mm to push after | ||||
|                             switching tool (default: 0) | ||||
|      | ||||
|        Cooling options: | ||||
|         --cooling           Enable fan and cooling control | ||||
|         --min-fan-speed     Minimum fan speed (default: 35%) | ||||
|         --max-fan-speed     Maximum fan speed (default: 100%) | ||||
|         --bridge-fan-speed  Fan speed to use when bridging (default: 100%) | ||||
|         --fan-below-layer-time Enable fan if layer print time is below this approximate number | ||||
|                             of seconds (default: 60) | ||||
|         --slowdown-below-layer-time Slow down if layer print time is below this approximate number | ||||
|                             of seconds (default: 30) | ||||
|         --min-print-speed   Minimum print speed (mm/s, default: 10) | ||||
|         --disable-fan-first-layers Disable fan for the first N layers (default: 1) | ||||
|         --fan-always-on     Keep fan always on at min fan speed, even for layers that don't need | ||||
|                             cooling | ||||
|      | ||||
|        Skirt options: | ||||
|         --skirts            Number of skirts to draw (0+, default: 1) | ||||
|         --skirt-distance    Distance in mm between innermost skirt and object | ||||
|                             (default: 6) | ||||
|         --skirt-height      Height of skirts to draw (expressed in layers, 0+, default: 1) | ||||
|         --min-skirt-length  Generate no less than the number of loops required to consume this length | ||||
|                             of filament on the first layer, for each extruder (mm, 0+, default: 0) | ||||
|         --brim-width        Width of the brim that will get added to each object to help adhesion | ||||
|                             (mm, default: 0) | ||||
|      | ||||
|        Transform options: | ||||
|         --scale             Factor for scaling input object (default: 1) | ||||
|         --rotate            Rotation angle in degrees (0-360, default: 0) | ||||
|         --duplicate         Number of items with auto-arrange (1+, default: 1) | ||||
|         --duplicate-grid    Number of items with grid arrangement (default: 1,1) | ||||
|         --duplicate-distance Distance in mm between copies (default: 6) | ||||
|         --dont-arrange      Don't arrange the objects on the build plate. The model coordinates | ||||
|                             define the absolute positions on the build plate.  | ||||
|                             The option --print-center will be ignored. | ||||
|         --xy-size-compensation | ||||
|                             Grow/shrink objects by the configured absolute distance (mm, default: 0) | ||||
|      | ||||
|        Sequential printing options: | ||||
|         --complete-objects  When printing multiple objects and/or copies, complete each one before | ||||
|                             starting the next one; watch out for extruder collisions (default: no) | ||||
|         --extruder-clearance-radius Radius in mm above which extruder won't collide with anything | ||||
|                             (default: 20) | ||||
|         --extruder-clearance-height Maximum vertical extruder depth; i.e. vertical distance from | ||||
|                             extruder tip and carriage bottom (default: 20) | ||||
|      | ||||
|        Miscellaneous options: | ||||
|         --notes             Notes to be added as comments to the output file | ||||
|         --resolution        Minimum detail resolution (mm, set zero for full resolution, default: 0) | ||||
|      | ||||
|        Flow options (advanced): | ||||
|         --extrusion-width   Set extrusion width manually; it accepts either an absolute value in mm | ||||
|                             (like 0.65) or a percentage over layer height (like 200%) | ||||
|         --first-layer-extrusion-width | ||||
|                             Set a different extrusion width for first layer | ||||
|         --perimeter-extrusion-width | ||||
|                             Set a different extrusion width for perimeters | ||||
|         --external-perimeter-extrusion-width | ||||
|                             Set a different extrusion width for external perimeters | ||||
|         --infill-extrusion-width | ||||
|                             Set a different extrusion width for infill | ||||
|         --solid-infill-extrusion-width | ||||
|                             Set a different extrusion width for solid infill | ||||
|         --top-infill-extrusion-width | ||||
|                             Set a different extrusion width for top infill | ||||
|         --support-material-extrusion-width | ||||
|                             Set a different extrusion width for support material | ||||
|         --infill-overlap    Overlap between infill and perimeters (default: 15%) | ||||
|         --bridge-flow-ratio Multiplier for extrusion when bridging (> 0, default: 1) | ||||
|      | ||||
|        Multiple extruder options: | ||||
|         --extruder-offset   Offset of each extruder, if firmware doesn't handle the displacement | ||||
|                             (can be specified multiple times, default: 0x0) | ||||
|         --perimeter-extruder | ||||
|                             Extruder to use for perimeters and brim (1+, default: 1) | ||||
|         --infill-extruder   Extruder to use for infill (1+, default: 1) | ||||
|         --solid-infill-extruder   Extruder to use for solid infill (1+, default: 1) | ||||
|         --support-material-extruder | ||||
|                             Extruder to use for support material, raft and skirt (1+, default: 1) | ||||
|         --support-material-interface-extruder | ||||
|                             Extruder to use for support material interface (1+, default: 1) | ||||
|                             --ooze-prevention   Drop temperature and park extruders outside a full skirt for automatic wiping | ||||
|                             (default: no) | ||||
|         --ooze-prevention   Drop temperature and park extruders outside a full skirt for automatic wiping | ||||
|                             (default: no) | ||||
|         --standby-temperature-delta | ||||
|                             Temperature difference to be applied when an extruder is not active and | ||||
|                             --ooze-prevention is enabled (default: -5) | ||||
| 
 | ||||
| 
 | ||||
| If you want to change a preset file, just do | ||||
| 
 | ||||
|     slic3r.pl --load config.ini --layer-height 0.25 --save config.ini | ||||
| 
 | ||||
| If you want to slice a file overriding an option contained in your preset file: | ||||
| 
 | ||||
|     slic3r.pl --load config.ini --layer-height 0.25 file.stl | ||||
| Please refer to the [Command Line Interface](https://github.com/prusa3d/Slic3r/wiki/Command-Line-Interface) wiki page. | ||||
|  |  | |||
							
								
								
									
										15
									
								
								resources/icons/cross.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,15 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="cross"> | ||||
| 	<g> | ||||
| 		 | ||||
| 			<line fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="2" y2="14"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		 | ||||
| 			<line fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="2" y1="2" x2="14" y2="14"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 659 B | 
							
								
								
									
										10
									
								
								resources/icons/flag_green.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,10 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="flag_x5F_green"> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="14" y2="14"/> | ||||
| 	<path fill="#8CC63F" d="M13,2C8.2,2,5.8,4.4,1,4.4v7.2c4.8,0,7.2-2.4,12-2.4V2z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 591 B | 
							
								
								
									
										10
									
								
								resources/icons/flag_red.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,10 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="flag_x5F_red"> | ||||
| 	 | ||||
| 		<line fill="none" stroke="#808080" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" x1="14" y1="2" x2="14" y2="14"/> | ||||
| 	<path fill="#ED1C24" d="M13,2C8.2,2,5.8,4.4,1,4.4v7.2c4.8,0,7.2-2.4,12-2.4V2z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 589 B | 
							
								
								
									
										27
									
								
								resources/icons/layers_white.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,27 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="layers"> | ||||
| 	<g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="13" fill="#FFFFFF" width="14" height="2"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="10.6" fill="#FFFFFF" width="14" height="1.74"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="8.19" fill="#FFFFFF" width="14" height="1.47"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="5.79" fill="#ED6B21" width="14" height="1.2"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="3.39" fill="#ED6B21" width="14" height="0.93"/> | ||||
| 		</g> | ||||
| 		<g> | ||||
| 			<rect x="1" y="0.99" fill="#FFFFFF" width="14" height="0.67"/> | ||||
| 		</g> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 845 B | 
							
								
								
									
										10
									
								
								resources/icons/lock_closed.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,10 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="lock_x5F_closed"> | ||||
| 	<path fill="none" stroke="#808080" stroke-width="2" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2c1,0,3,0,4,0c2,0,2,2,2,2v4"/> | ||||
| 	<path fill="#808080" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91 | ||||
| 		c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 729 B | 
							
								
								
									
										10
									
								
								resources/icons/lock_closed_white.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,10 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="lock_x5F_closed"> | ||||
| 	<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2c1,0,3,0,4,0c2,0,2,2,2,2v4"/> | ||||
| 	<path fill="#FFFFFF" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91 | ||||
| 		c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 729 B | 
							
								
								
									
										11
									
								
								resources/icons/lock_open.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,11 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="lock_x5F_open"> | ||||
| 	<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M4,8V4c0,0,0-2,2-2 | ||||
| 		c1,0,3,0,4,0c2,0,2,2,2,2v1"/> | ||||
| 	<path fill="#ED6B21" d="M13,8H3C2.45,8,2,8.45,2,9v5c0,0.55,0.45,1,1,1h10c0.55,0,1-0.45,1-1V9C14,8.45,13.55,8,13,8z M10,12H8.91 | ||||
| 		c-0.21,0.58-0.76,1-1.41,1C6.67,13,6,12.33,6,11.5S6.67,10,7.5,10c0.65,0,1.2,0.42,1.41,1H10V12z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 753 B | 
							
								
								
									
										10
									
								
								resources/icons/question.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,10 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="question"> | ||||
| 	<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M4,5c0,0,0,0,0-1s1-2,2-2 | ||||
| 		s3,0,4,0c2,0,2,2,2,3v1c0,1-1,2-2,2S9,8,9,8s1,0,0,0s-2,1-2,2s0,1,0,1"/> | ||||
| 	<circle fill="#ED6B21" cx="7" cy="14" r="1"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 615 B | 
							
								
								
									
										10
									
								
								resources/icons/resin.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,10 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="resin"> | ||||
| 	<rect x="4" y="7" fill="#ED6B21" width="8" height="8"/> | ||||
| 	<path fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" d="M4.5,15h6.99c0.28,0,0.5-0.23,0.5-0.5V6 | ||||
| 		c0-1-2-1-2-2s0-1,0-1h1V1.5C11,1.23,10.77,1,10.5,1H5.5C5.23,1,5,1.23,5,1.5V3h1v1c0,1-2,1-2,2v8.5C4,14.77,4.23,15,4.5,15z"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 671 B | 
							
								
								
									
										24
									
								
								resources/icons/save.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,24 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="save"> | ||||
| 	<g> | ||||
| 		<path fill="#808080" d="M12,2c1.44,0,2,0.56,2,2v10L2,14L2,2H12 M12,1H2C1.45,1,1,1.45,1,2V14c0,0.55,0.45,1,1,1h12 | ||||
| 			c0.55,0,1-0.45,1-1l0-10C15,2,14,1,12,1L12,1z"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="8" x2="10" y2="8"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="10" x2="10" y2="10"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<line fill="none" stroke="#808080" stroke-linecap="round" stroke-miterlimit="10" x1="3" y1="12" x2="7" y2="12"/> | ||||
| 	</g> | ||||
| 	<g> | ||||
| 		<path fill="#ED6B21" d="M11,1H5C4.45,1,4,1.45,4,2V5c0,0.55,0.45,1,1,1H11c0.55,0,1-0.45,1-1V2C12,1.45,11.55,1,11,1z M6,4.5 | ||||
| 			C6,4.78,5.78,5,5.5,5S5,4.78,5,4.5v-2C5,2.22,5.22,2,5.5,2S6,2.22,6,2.5V4.5z"/> | ||||
| 	</g> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 1.1 KiB | 
							
								
								
									
										12
									
								
								resources/icons/undo.svg
									
										
									
									
									
										Normal file
									
								
							
							
						
						|  | @ -0,0 +1,12 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <!-- Generator: Adobe Illustrator 23.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0)  --> | ||||
| <svg version="1.0" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" | ||||
| 	 viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve"> | ||||
| <g id="undo"> | ||||
| 	<path fill="none" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-miterlimit="10" d="M3,11 | ||||
| 		c0.91,1.78,2.76,3,4.89,3c3.04,0,5.5-2.46,5.5-5.5c0-3.04-2.46-5.5-5.5-5.5c-0.17,0-0.34,0.01-0.5,0.03"/> | ||||
| 	 | ||||
| 		<polygon fill="#ED6B21" stroke="#ED6B21" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" points=" | ||||
| 		7.39,1 7.39,5 4.39,3 	"/> | ||||
| </g> | ||||
| </svg> | ||||
| After Width: | Height: | Size: 746 B | 
|  | @ -8,11 +8,17 @@ src/slic3r/GUI/ConfigWizard.cpp | |||
| src/slic3r/GUI/Field.cpp | ||||
| src/slic3r/GUI/FirmwareDialog.cpp | ||||
| src/slic3r/GUI/GLCanvas3D.cpp | ||||
| src/slic3r/GUI/GLGizmo.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoCut.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoFlatten.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoMove.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoRotate.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoScale.cpp | ||||
| src/slic3r/GUI/Gizmos/GLGizmoSlaSupports.cpp | ||||
| src/slic3r/GUI/GUI.cpp | ||||
| src/slic3r/GUI/GUI_App.cpp | ||||
| src/slic3r/GUI/GUI_ObjectList.cpp | ||||
| src/slic3r/GUI/GUI_ObjectManipulation.cpp | ||||
| src/slic3r/GUI/GUI_ObjectSettings.cpp | ||||
| src/slic3r/GUI/GUI_Preview.cpp | ||||
| src/slic3r/GUI/KBShortcutsDialog.cpp | ||||
| src/slic3r/GUI/MainFrame.cpp | ||||
|  | @ -23,15 +29,22 @@ src/slic3r/GUI/Preset.cpp | |||
| src/slic3r/GUI/PresetBundle.cpp | ||||
| src/slic3r/GUI/PresetHints.cpp | ||||
| src/slic3r/GUI/PrintHostDialogs.cpp | ||||
| src/slic3r/GUI/ProgressStatusBar.cpp | ||||
| src/slic3r/GUI/RammingChart.cpp | ||||
| src/slic3r/GUI/SysInfoDialog.cpp | ||||
| src/slic3r/GUI/Tab.cpp | ||||
| src/slic3r/GUI/Tab.hpp | ||||
| src/slic3r/GUI/UpdateDialogs.cpp | ||||
| src/slic3r/GUI/WipeTowerDialog.cpp | ||||
| src/slic3r/GUI/wxExtensions.cpp | ||||
| src/slic3r/Utils/Duet.cpp | ||||
| src/slic3r/Utils/OctoPrint.cpp | ||||
| src/slic3r/Utils/PresetUpdater.cpp | ||||
| src/slic3r/Utils/FixModelByWin10.cpp | ||||
| src/libslic3r/Zipper.cpp | ||||
| src/libslic3r/SLA/SLASupportTree.cpp | ||||
| src/libslic3r/Print.cpp | ||||
| src/libslic3r/SLAPrint.cpp | ||||
| src/libslic3r/PrintBase.cpp | ||||
| src/libslic3r/PrintConfig.cpp | ||||
| src/libslic3r/GCode/PreviewData.cpp | ||||
|  |  | |||
|  | @ -1455,4 +1455,28 @@ Transformation Transformation::operator * (const Transformation& other) const | |||
|     return Transformation(get_matrix() * other.get_matrix()); | ||||
| } | ||||
| 
 | ||||
| Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     return | ||||
|         // From the current coordinate system to world.
 | ||||
|         Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * | ||||
|         // From world to the initial coordinate system.
 | ||||
|         Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); | ||||
| } | ||||
| 
 | ||||
| // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
 | ||||
| double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Vec3d  axis  = angle_axis.axis(); | ||||
|     double angle = angle_axis.angle(); | ||||
| #ifndef NDEBUG | ||||
|     if (std::abs(angle) > 1e-8) { | ||||
|         assert(std::abs(axis.x()) < 1e-8); | ||||
|         assert(std::abs(axis.y()) < 1e-8); | ||||
|     } | ||||
| #endif /* NDEBUG */ | ||||
|     return (axis.z() < 0) ? -angle : angle; | ||||
| } | ||||
| 
 | ||||
| } } | ||||
|  |  | |||
|  | @ -262,6 +262,13 @@ public: | |||
|     Transformation operator * (const Transformation& other) const; | ||||
| }; | ||||
| 
 | ||||
| // Rotation when going from the first coordinate system with rotation rot_xyz_from applied
 | ||||
| // to a coordinate system with rot_xyz_to applied.
 | ||||
| extern Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); | ||||
| // Rotation by Z to align rot_xyz_from to rot_xyz_to.
 | ||||
| // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
 | ||||
| extern double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to); | ||||
| 
 | ||||
| } } | ||||
| 
 | ||||
| #endif | ||||
|  |  | |||
|  | @ -2260,11 +2260,33 @@ void PrintConfigDef::init_sla_params() | |||
|     def->mode = comExpert; | ||||
|     def->default_value = new ConfigOptionFloat(50.); | ||||
| 
 | ||||
|     def = this->add("printer_correction", coFloats); | ||||
|     def = this->add("relative_correction", coFloats); | ||||
|     def->label = L("Printer scaling correction"); | ||||
|     def->full_label = L("Printer scaling correction"); | ||||
|     def->tooltip  = L("Printer scaling correction"); | ||||
|     def->min = 0; | ||||
|     def->mode = comExpert; | ||||
|     def->default_value = new ConfigOptionFloats( { 1., 1., 1. } ); | ||||
|      | ||||
|     def = this->add("absolute_correction", coFloat); | ||||
|     def->label = L("Printer absolute correction"); | ||||
|     def->full_label = L("Printer absolute correction"); | ||||
|     def->tooltip  = L("Will inflate or deflate the sliced 2D polygons according " | ||||
|                       "to the sign of the correction."); | ||||
|     def->mode = comExpert; | ||||
|     def->default_value = new ConfigOptionFloat(0.0); | ||||
|      | ||||
|     def = this->add("gamma_correction", coFloat); | ||||
|     def->label = L("Printer gamma correction"); | ||||
|     def->full_label = L("Printer gamma correction"); | ||||
|     def->tooltip  = L("This will apply a gamma correction to the rasterized 2D " | ||||
|                       "polygons. A gamma value of zero means thresholding with " | ||||
|                       "the threshold in the middle. This behaviour eliminates " | ||||
|                       "antialiasing without losing holes in polygons."); | ||||
|     def->min = 0; | ||||
|     def->mode = comExpert; | ||||
|     def->default_value = new ConfigOptionFloat(1.0); | ||||
|      | ||||
| 
 | ||||
|     // SLA Material settings.
 | ||||
|     def = this->add("initial_layer_height", coFloat); | ||||
|  | @ -2296,16 +2318,11 @@ void PrintConfigDef::init_sla_params() | |||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloat(15); | ||||
| 
 | ||||
|     def = this->add("material_correction_printing", coFloats); | ||||
|     def->full_label = L("Correction for expansion when printing"); | ||||
|     def->tooltip  = L("Correction for expansion when printing"); | ||||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } ); | ||||
| 
 | ||||
|     def = this->add("material_correction_curing", coFloats); | ||||
|     def->full_label = L("Correction for expansion after curing"); | ||||
|     def->tooltip  = L("Correction for expansion after curing"); | ||||
|     def = this->add("material_correction", coFloats); | ||||
|     def->full_label = L("Correction for expansion"); | ||||
|     def->tooltip  = L("Correction for expansion"); | ||||
|     def->min = 0; | ||||
|     def->mode = comExpert; | ||||
|     def->default_value = new ConfigOptionFloats( { 1. , 1., 1. } ); | ||||
| 
 | ||||
|     def = this->add("material_notes", coString); | ||||
|  | @ -2490,7 +2507,7 @@ void PrintConfigDef::init_sla_params() | |||
|     def->tooltip = L("No support points will be placed closer than this threshold."); | ||||
|     def->sidetext = L("mm"); | ||||
|     def->min = 0; | ||||
|     def->default_value = new ConfigOptionFloat(0.f); | ||||
|     def->default_value = new ConfigOptionFloat(1.f); | ||||
| 
 | ||||
|     def = this->add("pad_enable", coBool); | ||||
|     def->label = L("Use pad"); | ||||
|  |  | |||
|  | @ -1056,16 +1056,14 @@ public: | |||
|     ConfigOptionFloat                       initial_layer_height; | ||||
|     ConfigOptionFloat                       exposure_time; | ||||
|     ConfigOptionFloat                       initial_exposure_time; | ||||
|     ConfigOptionFloats                      material_correction_printing; | ||||
|     ConfigOptionFloats                      material_correction_curing; | ||||
|     ConfigOptionFloats                      material_correction; | ||||
| protected: | ||||
|     void initialize(StaticCacheBase &cache, const char *base_ptr) | ||||
|     { | ||||
|         OPT_PTR(initial_layer_height); | ||||
|         OPT_PTR(exposure_time); | ||||
|         OPT_PTR(initial_exposure_time); | ||||
|         OPT_PTR(material_correction_printing); | ||||
|         OPT_PTR(material_correction_curing); | ||||
|         OPT_PTR(material_correction); | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
|  | @ -1081,7 +1079,9 @@ public: | |||
|     ConfigOptionInt                         display_pixels_x; | ||||
|     ConfigOptionInt                         display_pixels_y; | ||||
|     ConfigOptionEnum<SLADisplayOrientation> display_orientation; | ||||
|     ConfigOptionFloats                      printer_correction; | ||||
|     ConfigOptionFloats                      relative_correction; | ||||
|     ConfigOptionFloat                       absolute_correction; | ||||
|     ConfigOptionFloat                       gamma_correction; | ||||
|     ConfigOptionFloat                       fast_tilt_time; | ||||
|     ConfigOptionFloat                       slow_tilt_time; | ||||
|     ConfigOptionFloat                       area_fill; | ||||
|  | @ -1096,7 +1096,9 @@ protected: | |||
|         OPT_PTR(display_pixels_x); | ||||
|         OPT_PTR(display_pixels_y); | ||||
|         OPT_PTR(display_orientation); | ||||
|         OPT_PTR(printer_correction); | ||||
|         OPT_PTR(relative_correction); | ||||
|         OPT_PTR(absolute_correction); | ||||
|         OPT_PTR(gamma_correction); | ||||
|         OPT_PTR(fast_tilt_time); | ||||
|         OPT_PTR(slow_tilt_time); | ||||
|         OPT_PTR(area_fill); | ||||
|  |  | |||
|  | @ -138,6 +138,7 @@ template<> class FilePrinter<FilePrinterFormat::SLA_PNGZIP> | |||
|     double m_exp_time_s = .0, m_exp_time_first_s = .0; | ||||
|     double m_layer_height = .0; | ||||
|     Raster::Origin m_o = Raster::Origin::TOP_LEFT; | ||||
|     double m_gamma; | ||||
| 
 | ||||
|     double m_used_material = 0.0; | ||||
|     int    m_cnt_fade_layers = 0; | ||||
|  | @ -194,7 +195,8 @@ public: | |||
|                        unsigned width_px, unsigned height_px, | ||||
|                        double layer_height, | ||||
|                        double exp_time, double exp_time_first, | ||||
|                        RasterOrientation ro = RO_PORTRAIT): | ||||
|                        RasterOrientation ro = RO_PORTRAIT, | ||||
|                        double gamma = 1.0): | ||||
|         m_res(width_px, height_px), | ||||
|         m_pxdim(width_mm/width_px, height_mm/height_px), | ||||
|         m_exp_time_s(exp_time), | ||||
|  | @ -203,7 +205,8 @@ public: | |||
| 
 | ||||
|         // Here is the trick with the orientation.
 | ||||
|         m_o(ro == RO_LANDSCAPE? Raster::Origin::BOTTOM_LEFT : | ||||
|                                 Raster::Origin::TOP_LEFT ) | ||||
|                                 Raster::Origin::TOP_LEFT ), | ||||
|         m_gamma(gamma) | ||||
|     { | ||||
|     } | ||||
| 
 | ||||
|  | @ -228,12 +231,12 @@ public: | |||
| 
 | ||||
|     inline void begin_layer(unsigned lyr) { | ||||
|         if(m_layers_rst.size() <= lyr) m_layers_rst.resize(lyr+1); | ||||
|         m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_o); | ||||
|         m_layers_rst[lyr].raster.reset(m_res, m_pxdim, m_o, m_gamma); | ||||
|     } | ||||
| 
 | ||||
|     inline void begin_layer() { | ||||
|         m_layers_rst.emplace_back(); | ||||
|         m_layers_rst.front().raster.reset(m_res, m_pxdim, m_o); | ||||
|         m_layers_rst.front().raster.reset(m_res, m_pxdim, m_o, m_gamma); | ||||
|     } | ||||
| 
 | ||||
|     inline void finish_layer(unsigned lyr_id) { | ||||
|  |  | |||
|  | @ -19,6 +19,12 @@ | |||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| const Polygon& contour(const ExPolygon& p) { return p.contour; } | ||||
| const ClipperLib::Path& contour(const ClipperLib::Polygon& p) { return p.Contour; } | ||||
| 
 | ||||
| const Polygons& holes(const ExPolygon& p) { return p.holes; } | ||||
| const ClipperLib::Paths& holes(const ClipperLib::Polygon& p) { return p.Holes; } | ||||
| 
 | ||||
| class Raster::Impl { | ||||
| public: | ||||
|     using TPixelRenderer = agg::pixfmt_gray8; // agg::pixfmt_rgb24;
 | ||||
|  | @ -37,14 +43,17 @@ public: | |||
| 
 | ||||
| private: | ||||
|     Raster::Resolution m_resolution; | ||||
|     Raster::PixelDim m_pxdim; | ||||
| //    Raster::PixelDim m_pxdim;
 | ||||
|     Raster::PixelDim m_pxdim_scaled;    // used for scaled coordinate polygons
 | ||||
|     TBuffer m_buf; | ||||
|     TRawBuffer m_rbuf; | ||||
|     TPixelRenderer m_pixfmt; | ||||
|     TRawRenderer m_raw_renderer; | ||||
|     TRendererAA m_renderer; | ||||
|      | ||||
|     std::function<double(double)> m_gammafn; | ||||
|     Origin m_o; | ||||
| 
 | ||||
|      | ||||
|     inline void flipy(agg::path_storage& path) const { | ||||
|         path.flip_y(0, m_resolution.height_px); | ||||
|     } | ||||
|  | @ -52,8 +61,10 @@ private: | |||
| public: | ||||
| 
 | ||||
|     inline Impl(const Raster::Resolution& res, const Raster::PixelDim &pd, | ||||
|                 Origin o): | ||||
|         m_resolution(res), m_pxdim(pd), | ||||
|                 Origin o, double gamma = 1.0): | ||||
|         m_resolution(res),  | ||||
| //        m_pxdim(pd), 
 | ||||
|         m_pxdim_scaled(SCALING_FACTOR / pd.w_mm, SCALING_FACTOR / pd.h_mm), | ||||
|         m_buf(res.pixels()), | ||||
|         m_rbuf(reinterpret_cast<TPixelRenderer::value_type*>(m_buf.data()), | ||||
|               res.width_px, res.height_px, | ||||
|  | @ -64,43 +75,26 @@ public: | |||
|         m_o(o) | ||||
|     { | ||||
|         m_renderer.color(ColorWhite); | ||||
| 
 | ||||
|         // If we would like to play around with gamma
 | ||||
|         // ras.gamma(agg::gamma_power(1.0));
 | ||||
| 
 | ||||
|          | ||||
|         if(gamma > 0) m_gammafn = agg::gamma_power(gamma); | ||||
|         else m_gammafn = agg::gamma_threshold(0.5); | ||||
|          | ||||
|         clear(); | ||||
|     } | ||||
| 
 | ||||
|     void draw(const ExPolygon &poly) { | ||||
|     template<class P> void draw(const P &poly) { | ||||
|         agg::rasterizer_scanline_aa<> ras; | ||||
|         agg::scanline_p8 scanlines; | ||||
|          | ||||
|         ras.gamma(m_gammafn); | ||||
| 
 | ||||
|         auto&& path = to_path(poly.contour); | ||||
|         auto&& path = to_path(contour(poly)); | ||||
| 
 | ||||
|         if(m_o == Origin::TOP_LEFT) flipy(path); | ||||
| 
 | ||||
|         ras.add_path(path); | ||||
| 
 | ||||
|         for(auto h : poly.holes) { | ||||
|             auto&& holepath = to_path(h); | ||||
|             if(m_o == Origin::TOP_LEFT) flipy(holepath); | ||||
|             ras.add_path(holepath); | ||||
|         } | ||||
| 
 | ||||
|         agg::render_scanlines(ras, scanlines, m_renderer); | ||||
|     } | ||||
| 
 | ||||
|     void draw(const ClipperLib::Polygon &poly) { | ||||
|         agg::rasterizer_scanline_aa<> ras; | ||||
|         agg::scanline_p8 scanlines; | ||||
| 
 | ||||
|         auto&& path = to_path(poly.Contour); | ||||
| 
 | ||||
|         if(m_o == Origin::TOP_LEFT) flipy(path); | ||||
| 
 | ||||
|         ras.add_path(path); | ||||
| 
 | ||||
|         for(auto h : poly.Holes) { | ||||
|         for(auto& h : holes(poly)) { | ||||
|             auto&& holepath = to_path(h); | ||||
|             if(m_o == Origin::TOP_LEFT) flipy(holepath); | ||||
|             ras.add_path(holepath); | ||||
|  | @ -120,40 +114,34 @@ public: | |||
|     inline Origin origin() const /*noexcept*/ { return m_o; } | ||||
| 
 | ||||
| private: | ||||
|     double getPx(const Point& p) { | ||||
|         return p(0) * SCALING_FACTOR/m_pxdim.w_mm; | ||||
|     inline double getPx(const Point& p) { | ||||
|         return p(0) * m_pxdim_scaled.w_mm; | ||||
|     } | ||||
| 
 | ||||
|     double getPy(const Point& p) { | ||||
|         return p(1) * SCALING_FACTOR/m_pxdim.h_mm; | ||||
|     inline double getPy(const Point& p) { | ||||
|         return p(1) * m_pxdim_scaled.h_mm; | ||||
|     } | ||||
| 
 | ||||
|     agg::path_storage to_path(const Polygon& poly) | ||||
|     { | ||||
|         agg::path_storage path; | ||||
| 
 | ||||
|         auto it = poly.points.begin(); | ||||
|         path.move_to(getPx(*it), getPy(*it)); | ||||
|         while(++it != poly.points.end()) path.line_to(getPx(*it), getPy(*it)); | ||||
|         path.line_to(getPx(poly.points.front()), getPy(poly.points.front())); | ||||
| 
 | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     double getPx(const ClipperLib::IntPoint& p) { | ||||
|         return p.X * SCALING_FACTOR/m_pxdim.w_mm; | ||||
|     } | ||||
| 
 | ||||
|     double getPy(const ClipperLib::IntPoint& p) { | ||||
|         return p.Y * SCALING_FACTOR/m_pxdim.h_mm; | ||||
|     } | ||||
| 
 | ||||
|     agg::path_storage to_path(const ClipperLib::Path& poly) | ||||
|     inline agg::path_storage to_path(const Polygon& poly) | ||||
|     { | ||||
|         return to_path(poly.points); | ||||
|     } | ||||
| 
 | ||||
|     inline double getPx(const ClipperLib::IntPoint& p) { | ||||
|         return p.X * m_pxdim_scaled.w_mm; | ||||
|     } | ||||
| 
 | ||||
|     inline double getPy(const ClipperLib::IntPoint& p) { | ||||
|         return p.Y * m_pxdim_scaled.h_mm; | ||||
|     } | ||||
| 
 | ||||
|     template<class PointVec> agg::path_storage to_path(const PointVec& poly) | ||||
|     { | ||||
|         agg::path_storage path; | ||||
|          | ||||
|         auto it = poly.begin(); | ||||
|         path.move_to(getPx(*it), getPy(*it)); | ||||
|          | ||||
|         while(++it != poly.end()) | ||||
|             path.line_to(getPx(*it), getPy(*it)); | ||||
| 
 | ||||
|  | @ -166,8 +154,8 @@ private: | |||
| const Raster::Impl::TPixel Raster::Impl::ColorWhite = Raster::Impl::TPixel(255); | ||||
| const Raster::Impl::TPixel Raster::Impl::ColorBlack = Raster::Impl::TPixel(0); | ||||
| 
 | ||||
| Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o): | ||||
|     m_impl(new Impl(r, pd, o)) {} | ||||
| Raster::Raster(const Resolution &r, const PixelDim &pd, Origin o, double g): | ||||
|     m_impl(new Impl(r, pd, o, g)) {} | ||||
| 
 | ||||
| Raster::Raster() {} | ||||
| 
 | ||||
|  | @ -176,19 +164,20 @@ Raster::~Raster() {} | |||
| Raster::Raster(Raster &&m): | ||||
|     m_impl(std::move(m.m_impl)) {} | ||||
| 
 | ||||
| void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd) | ||||
| void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd,  | ||||
|                    double g) | ||||
| { | ||||
|     // Free up the unnecessary memory and make sure it stays clear after
 | ||||
|     // an exception
 | ||||
|     auto o = m_impl? m_impl->origin() : Origin::TOP_LEFT; | ||||
|     reset(r, pd, o); | ||||
|     reset(r, pd, o, g); | ||||
| } | ||||
| 
 | ||||
| void Raster::reset(const Raster::Resolution &r, const Raster::PixelDim &pd, | ||||
|                    Raster::Origin o) | ||||
|                    Raster::Origin o, double gamma) | ||||
| { | ||||
|     m_impl.reset(); | ||||
|     m_impl.reset(new Impl(r, pd, o)); | ||||
|     m_impl.reset(new Impl(r, pd, o, gamma)); | ||||
| } | ||||
| 
 | ||||
| void Raster::reset() | ||||
|  |  | |||
|  | @ -99,8 +99,9 @@ public: | |||
|     }; | ||||
| 
 | ||||
|     /// Constructor taking the resolution and the pixel dimension.
 | ||||
|     explicit Raster(const Resolution& r, const PixelDim& pd, | ||||
|                     Origin o = Origin::BOTTOM_LEFT ); | ||||
|     Raster(const Resolution& r,  const PixelDim& pd,  | ||||
|            Origin o = Origin::BOTTOM_LEFT, double gamma = 1.0); | ||||
|      | ||||
|     Raster(); | ||||
|     Raster(const Raster& cpy) = delete; | ||||
|     Raster& operator=(const Raster& cpy) = delete; | ||||
|  | @ -108,8 +109,8 @@ public: | |||
|     ~Raster(); | ||||
| 
 | ||||
|     /// Reallocated everything for the given resolution and pixel dimension.
 | ||||
|     void reset(const Resolution& r, const PixelDim& pd); | ||||
|     void reset(const Resolution& r, const PixelDim& pd, Origin o); | ||||
|     void reset(const Resolution& r, const PixelDim& pd, double gamma = 1.0); | ||||
|     void reset(const Resolution& r, const PixelDim& pd, Origin o, double gamma); | ||||
| 
 | ||||
|     /**
 | ||||
|      * Release the allocated resources. Drawing in this state ends in | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ public: | |||
|             float minimal_distance; | ||||
|             float head_diameter; | ||||
|             ///////////////
 | ||||
|             inline float support_force() const { return 10.f / density_relative; } // a force one point can support       (arbitrary force unit)
 | ||||
|             inline float support_force() const { return 7.7f / density_relative; } // a force one point can support       (arbitrary force unit)
 | ||||
|             inline float tear_pressure() const { return 1.f; }  // pressure that the display exerts    (the force unit per mm2)
 | ||||
|         }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| #include "SLA/SLABasePool.hpp" | ||||
| #include "SLA/SLAAutoSupports.hpp" | ||||
| #include "ClipperUtils.hpp" | ||||
| #include "Geometry.hpp" | ||||
| #include "MTUtils.hpp" | ||||
| 
 | ||||
| #include <unordered_set> | ||||
|  | @ -85,17 +86,32 @@ void SLAPrint::clear() | |||
| } | ||||
| 
 | ||||
| // Transformation without rotation around Z and without a shift by X and Y.
 | ||||
| static Transform3d sla_trafo(const ModelObject &model_object) | ||||
| static Transform3d sla_trafo(const SLAPrint& p, const ModelObject &model_object) | ||||
| { | ||||
| 
 | ||||
|     Vec3d corr = p.relative_correction(); | ||||
| 
 | ||||
|     ModelInstance &model_instance = *model_object.instances.front(); | ||||
|     Vec3d          offset         = model_instance.get_offset(); | ||||
|     Vec3d          rotation       = model_instance.get_rotation(); | ||||
|     offset(0) = 0.; | ||||
|     offset(1) = 0.; | ||||
|     rotation(2) = 0.; | ||||
|     Transform3d trafo = Geometry::assemble_transform(offset, rotation, model_instance.get_scaling_factor(), model_instance.get_mirror()); | ||||
| 	if (model_instance.is_left_handed()) | ||||
| 		trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo; | ||||
| 
 | ||||
|     offset(Z) *= corr(Z); | ||||
| 
 | ||||
|     auto trafo = Transform3d::Identity(); | ||||
|     trafo.translate(offset); | ||||
|     trafo.scale(corr); | ||||
|     trafo.rotate(Eigen::AngleAxisd(rotation(2), Vec3d::UnitZ())); | ||||
|     trafo.rotate(Eigen::AngleAxisd(rotation(1), Vec3d::UnitY())); | ||||
|     trafo.rotate(Eigen::AngleAxisd(rotation(0), Vec3d::UnitX())); | ||||
|     trafo.scale(model_instance.get_scaling_factor()); | ||||
|     trafo.scale(model_instance.get_mirror()); | ||||
| 
 | ||||
|     if (model_instance.is_left_handed()) | ||||
|         trafo = Eigen::Scaling(Vec3d(-1., 1., 1.)) * trafo; | ||||
| 
 | ||||
|     return trafo; | ||||
| } | ||||
| 
 | ||||
|  | @ -103,13 +119,18 @@ static Transform3d sla_trafo(const ModelObject &model_object) | |||
| static std::vector<SLAPrintObject::Instance> sla_instances(const ModelObject &model_object) | ||||
| { | ||||
|     std::vector<SLAPrintObject::Instance> instances; | ||||
|     for (ModelInstance *model_instance : model_object.instances) | ||||
|         if (model_instance->is_printable()) { | ||||
|             instances.emplace_back( | ||||
|                 model_instance->id(), | ||||
|                 Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), | ||||
|                 float(model_instance->get_rotation(Z))); | ||||
|         } | ||||
|     assert(! model_object.instances.empty()); | ||||
|     if (! model_object.instances.empty()) { | ||||
|         Vec3d rotation0 = model_object.instances.front()->get_rotation(); | ||||
|         rotation0(2) = 0.; | ||||
|         for (ModelInstance *model_instance : model_object.instances) | ||||
|             if (model_instance->is_printable()) { | ||||
|                 instances.emplace_back( | ||||
|                     model_instance->id(), | ||||
|                     Point::new_scale(model_instance->get_offset(X), model_instance->get_offset(Y)), | ||||
| 					float(Geometry::rotation_diff_z(rotation0, model_instance->get_rotation()))); | ||||
|             } | ||||
|     } | ||||
|     return instances; | ||||
| } | ||||
| 
 | ||||
|  | @ -121,12 +142,12 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
| 
 | ||||
|     // Make a copy of the config, normalize it.
 | ||||
|     DynamicPrintConfig config(config_in); | ||||
| 	config.option("sla_print_settings_id",    true); | ||||
| 	config.option("sla_material_settings_id", true); | ||||
| 	config.option("printer_settings_id",      true); | ||||
|     config.option("sla_print_settings_id",    true); | ||||
|     config.option("sla_material_settings_id", true); | ||||
|     config.option("printer_settings_id",      true); | ||||
|     config.normalize(); | ||||
|     // Collect changes to print config.
 | ||||
|     t_config_option_keys print_diff    = m_print_config.diff(config);     | ||||
|     t_config_option_keys print_diff    = m_print_config.diff(config); | ||||
|     t_config_option_keys printer_diff  = m_printer_config.diff(config); | ||||
|     t_config_option_keys material_diff = m_material_config.diff(config); | ||||
|     t_config_option_keys object_diff   = m_default_object_config.diff(config); | ||||
|  | @ -143,23 +164,24 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
|     tbb::mutex::scoped_lock lock(this->state_mutex()); | ||||
| 
 | ||||
|     // The following call may stop the background processing.
 | ||||
|     bool invalidate_all_model_objects = false; | ||||
|     if (! print_diff.empty()) | ||||
|         update_apply_status(this->invalidate_state_by_config_options(print_diff)); | ||||
|         update_apply_status(this->invalidate_state_by_config_options(print_diff, invalidate_all_model_objects)); | ||||
|     if (! printer_diff.empty()) | ||||
|         update_apply_status(this->invalidate_state_by_config_options(printer_diff)); | ||||
|         update_apply_status(this->invalidate_state_by_config_options(printer_diff, invalidate_all_model_objects)); | ||||
|     if (! material_diff.empty()) | ||||
|         update_apply_status(this->invalidate_state_by_config_options(material_diff)); | ||||
|         update_apply_status(this->invalidate_state_by_config_options(material_diff, invalidate_all_model_objects)); | ||||
| 
 | ||||
|     // Apply variables to placeholder parser. The placeholder parser is currently used
 | ||||
|     // only to generate the output file name.
 | ||||
| 	if (! placeholder_parser_diff.empty()) { | ||||
|     if (! placeholder_parser_diff.empty()) { | ||||
|         // update_apply_status(this->invalidate_step(slapsRasterize));
 | ||||
| 		PlaceholderParser &pp = this->placeholder_parser(); | ||||
| 		pp.apply_config(config); | ||||
|         PlaceholderParser &pp = this->placeholder_parser(); | ||||
|         pp.apply_config(config); | ||||
|         // Set the profile aliases for the PrintBase::output_filename()
 | ||||
| 		pp.set("print_preset",    config.option("sla_print_settings_id")->clone()); | ||||
| 		pp.set("material_preset", config.option("sla_material_settings_id")->clone()); | ||||
| 		pp.set("printer_preset",  config.option("printer_settings_id")->clone()); | ||||
|         pp.set("print_preset",    config.option("sla_print_settings_id")->clone()); | ||||
|         pp.set("material_preset", config.option("sla_material_settings_id")->clone()); | ||||
|         pp.set("printer_preset",  config.option("printer_settings_id")->clone()); | ||||
|     } | ||||
| 
 | ||||
|     // It is also safe to change m_config now after this->invalidate_state_by_config_options() call.
 | ||||
|  | @ -187,7 +209,7 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
|     std::set<ModelObjectStatus> model_object_status; | ||||
| 
 | ||||
|     // 1) Synchronize model objects.
 | ||||
|     if (model.id() != m_model.id()) { | ||||
|     if (model.id() != m_model.id() || invalidate_all_model_objects) { | ||||
|         // Kill everything, initialize from scratch.
 | ||||
|         // Stop background processing.
 | ||||
|         this->call_cancel_callback(); | ||||
|  | @ -306,106 +328,91 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
|         auto it_status = model_object_status.find(ModelObjectStatus(model_object.id())); | ||||
|         assert(it_status != model_object_status.end()); | ||||
|         assert(it_status->status != ModelObjectStatus::Deleted); | ||||
| 		// PrintObject for this ModelObject, if it exists.
 | ||||
| 		auto it_print_object_status = print_object_status.end(); | ||||
| 		if (it_status->status != ModelObjectStatus::New) { | ||||
| 			// Update the ModelObject instance, possibly invalidate the linked PrintObjects.
 | ||||
| 			assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved); | ||||
| 			const ModelObject &model_object_new       = *model.objects[idx_model_object]; | ||||
| 			it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id())); | ||||
| 			if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id()) | ||||
| 				it_print_object_status = print_object_status.end(); | ||||
| 			// Check whether a model part volume was added or removed, their transformations or order changed.
 | ||||
| 			bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); | ||||
| 			bool sla_trafo_differs  =  | ||||
| 				model_object.instances.empty() != model_object_new.instances.empty() || | ||||
| 				(! model_object.instances.empty() &&  | ||||
| 				  (! sla_trafo(model_object).isApprox(sla_trafo(model_object_new)) ||  | ||||
| 				    model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed())); | ||||
| 			if (model_parts_differ || sla_trafo_differs) { | ||||
| 				// The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
 | ||||
| 				if (it_print_object_status != print_object_status.end()) { | ||||
| 					update_apply_status(it_print_object_status->print_object->invalidate_all_steps()); | ||||
| 					const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted; | ||||
| 				} | ||||
| 				// Copy content of the ModelObject including its ID, do not change the parent.
 | ||||
| 				model_object.assign_copy(model_object_new); | ||||
| 			} else { | ||||
| 				// Synchronize Object's config.
 | ||||
| 				bool object_config_changed = model_object.config != model_object_new.config; | ||||
| 				if (object_config_changed) | ||||
| 					model_object.config = model_object_new.config; | ||||
| 				if (! object_diff.empty() || object_config_changed) { | ||||
| 					SLAPrintObjectConfig new_config = m_default_object_config; | ||||
| 					normalize_and_apply_config(new_config, model_object.config); | ||||
| 					if (it_print_object_status != print_object_status.end()) { | ||||
| 						t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config); | ||||
| 						if (! diff.empty()) { | ||||
| 							update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff)); | ||||
| 							it_print_object_status->print_object->config_apply_only(new_config, diff, true); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				/*if (model_object.sla_support_points != model_object_new.sla_support_points) {
 | ||||
| 					model_object.sla_support_points = model_object_new.sla_support_points; | ||||
| 					if (it_print_object_status != print_object_status.end()) | ||||
| 						update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
| 				} | ||||
| 				if (model_object.sla_points_status != model_object_new.sla_points_status) { | ||||
| 					// Change of this status should invalidate support points. The points themselves are not enough, there are none
 | ||||
| 					// in case that nothing was generated OR that points were autogenerated already and not copied to the front-end.
 | ||||
| 					// These cases can only be differentiated by checking the status change. However, changing from 'Generating' should NOT
 | ||||
| 					// invalidate - that would keep stopping the background processing without a reason.
 | ||||
| 					if (model_object.sla_points_status != sla::PointsStatus::Generating) | ||||
| 						if (it_print_object_status != print_object_status.end()) | ||||
| 							update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
| 					model_object.sla_points_status = model_object_new.sla_points_status; | ||||
| 				}*/ | ||||
|         // PrintObject for this ModelObject, if it exists.
 | ||||
|         auto it_print_object_status = print_object_status.end(); | ||||
|         if (it_status->status != ModelObjectStatus::New) { | ||||
|             // Update the ModelObject instance, possibly invalidate the linked PrintObjects.
 | ||||
|             assert(it_status->status == ModelObjectStatus::Old || it_status->status == ModelObjectStatus::Moved); | ||||
|             const ModelObject &model_object_new       = *model.objects[idx_model_object]; | ||||
|             it_print_object_status = print_object_status.lower_bound(PrintObjectStatus(model_object.id())); | ||||
|             if (it_print_object_status != print_object_status.end() && it_print_object_status->id != model_object.id()) | ||||
|                 it_print_object_status = print_object_status.end(); | ||||
|             // Check whether a model part volume was added or removed, their transformations or order changed.
 | ||||
|             bool model_parts_differ = model_volume_list_changed(model_object, model_object_new, ModelVolumeType::MODEL_PART); | ||||
|             bool sla_trafo_differs  = | ||||
|                 model_object.instances.empty() != model_object_new.instances.empty() || | ||||
|                 (! model_object.instances.empty() && | ||||
|                   (! sla_trafo(*this, model_object).isApprox(sla_trafo(*this, model_object_new)) || | ||||
|                     model_object.instances.front()->is_left_handed() != model_object_new.instances.front()->is_left_handed())); | ||||
|             if (model_parts_differ || sla_trafo_differs) { | ||||
|                 // The very first step (the slicing step) is invalidated. One may freely remove all associated PrintObjects.
 | ||||
|                 if (it_print_object_status != print_object_status.end()) { | ||||
|                     update_apply_status(it_print_object_status->print_object->invalidate_all_steps()); | ||||
|                     const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted; | ||||
|                 } | ||||
|                 // Copy content of the ModelObject including its ID, do not change the parent.
 | ||||
|                 model_object.assign_copy(model_object_new); | ||||
|             } else { | ||||
|                 // Synchronize Object's config.
 | ||||
|                 bool object_config_changed = model_object.config != model_object_new.config; | ||||
|                 if (object_config_changed) | ||||
|                     model_object.config = model_object_new.config; | ||||
|                 if (! object_diff.empty() || object_config_changed) { | ||||
|                     SLAPrintObjectConfig new_config = m_default_object_config; | ||||
|                     normalize_and_apply_config(new_config, model_object.config); | ||||
|                     if (it_print_object_status != print_object_status.end()) { | ||||
|                         t_config_option_keys diff = it_print_object_status->print_object->config().diff(new_config); | ||||
|                         if (! diff.empty()) { | ||||
|                             update_apply_status(it_print_object_status->print_object->invalidate_state_by_config_options(diff)); | ||||
|                             it_print_object_status->print_object->config_apply_only(new_config, diff, true); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
| 				bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified; | ||||
| 				bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified; | ||||
| 				if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
 | ||||
| 					(! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
 | ||||
| 					(new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) { | ||||
| 					if (it_print_object_status != print_object_status.end()) | ||||
| 						update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
|                 bool old_user_modified = model_object.sla_points_status == sla::PointsStatus::UserModified; | ||||
|                 bool new_user_modified = model_object_new.sla_points_status == sla::PointsStatus::UserModified; | ||||
|                 if ((old_user_modified && ! new_user_modified) || // switching to automatic supports from manual supports
 | ||||
|                     (! old_user_modified && new_user_modified) || // switching to manual supports from automatic supports
 | ||||
|                     (new_user_modified && model_object.sla_support_points != model_object_new.sla_support_points)) { | ||||
|                     if (it_print_object_status != print_object_status.end()) | ||||
|                         update_apply_status(it_print_object_status->print_object->invalidate_step(slaposSupportPoints)); | ||||
| 
 | ||||
| 					model_object.sla_points_status = model_object_new.sla_points_status; | ||||
| 					model_object.sla_support_points = model_object_new.sla_support_points; | ||||
| 				} | ||||
|                     model_object.sla_points_status = model_object_new.sla_points_status; | ||||
|                     model_object.sla_support_points = model_object_new.sla_support_points; | ||||
|                 } | ||||
| 
 | ||||
| 				// Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
 | ||||
| 				model_object.name       = model_object_new.name; | ||||
| 				model_object.input_file = model_object_new.input_file; | ||||
| 				model_object.clear_instances(); | ||||
| 				model_object.instances.reserve(model_object_new.instances.size()); | ||||
| 				for (const ModelInstance *model_instance : model_object_new.instances) { | ||||
| 					model_object.instances.emplace_back(new ModelInstance(*model_instance)); | ||||
| 					model_object.instances.back()->set_model_object(&model_object); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|                 // Copy the ModelObject name, input_file and instances. The instances will compared against PrintObject instances in the next step.
 | ||||
|                 model_object.name       = model_object_new.name; | ||||
|                 model_object.input_file = model_object_new.input_file; | ||||
|                 model_object.clear_instances(); | ||||
|                 model_object.instances.reserve(model_object_new.instances.size()); | ||||
|                 for (const ModelInstance *model_instance : model_object_new.instances) { | ||||
|                     model_object.instances.emplace_back(new ModelInstance(*model_instance)); | ||||
|                     model_object.instances.back()->set_model_object(&model_object); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         std::vector<SLAPrintObject::Instance> new_instances = sla_instances(model_object); | ||||
|         if (it_print_object_status != print_object_status.end() && it_print_object_status->status != PrintObjectStatus::Deleted) { | ||||
|             // The SLAPrintObject is already there.
 | ||||
| 			if (new_instances.empty()) { | ||||
| 				const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted; | ||||
| 			} else { | ||||
| 				if (new_instances != it_print_object_status->print_object->instances()) { | ||||
| 					// Instances changed.
 | ||||
| 					it_print_object_status->print_object->set_instances(new_instances); | ||||
|             if (new_instances.empty()) { | ||||
|                 const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Deleted; | ||||
|             } else { | ||||
|                 if (new_instances != it_print_object_status->print_object->instances()) { | ||||
|                     // Instances changed.
 | ||||
|                     it_print_object_status->print_object->set_instances(new_instances); | ||||
|                     update_apply_status(this->invalidate_step(slapsMergeSlicesAndEval)); | ||||
| 				} | ||||
| 				print_objects_new.emplace_back(it_print_object_status->print_object); | ||||
| 				const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused; | ||||
| 			} | ||||
| 		} else if (! new_instances.empty()) { | ||||
|                 } | ||||
|                 print_objects_new.emplace_back(it_print_object_status->print_object); | ||||
|                 const_cast<PrintObjectStatus&>(*it_print_object_status).status = PrintObjectStatus::Reused; | ||||
|             } | ||||
|         } else if (! new_instances.empty()) { | ||||
|             auto print_object = new SLAPrintObject(this, &model_object); | ||||
| 
 | ||||
|             // FIXME: this invalidates the transformed mesh in SLAPrintObject
 | ||||
|             // which is expensive to calculate (especially the raw_mesh() call)
 | ||||
|             print_object->set_trafo(sla_trafo(model_object), model_object.instances.front()->is_left_handed()); | ||||
|             print_object->set_trafo(sla_trafo(*this, model_object), model_object.instances.front()->is_left_handed()); | ||||
| 
 | ||||
|             print_object->set_instances(std::move(new_instances)); | ||||
|             print_object->config_apply(config, true); | ||||
|  | @ -440,56 +447,56 @@ SLAPrint::ApplyStatus SLAPrint::apply(const Model &model, const DynamicPrintConf | |||
| // After calling the apply() function, set_task() may be called to limit the task to be processed by process().
 | ||||
| void SLAPrint::set_task(const TaskParams ¶ms) | ||||
| { | ||||
| 	// Grab the lock for the Print / PrintObject milestones.
 | ||||
| 	tbb::mutex::scoped_lock lock(this->state_mutex()); | ||||
|     // Grab the lock for the Print / PrintObject milestones.
 | ||||
|     tbb::mutex::scoped_lock lock(this->state_mutex()); | ||||
| 
 | ||||
| 	int n_object_steps = int(params.to_object_step) + 1; | ||||
| 	if (n_object_steps == 0) | ||||
| 		n_object_steps = (int)slaposCount; | ||||
|     int n_object_steps = int(params.to_object_step) + 1; | ||||
|     if (n_object_steps == 0) | ||||
|         n_object_steps = (int)slaposCount; | ||||
| 
 | ||||
| 	if (params.single_model_object.valid()) { | ||||
|     if (params.single_model_object.valid()) { | ||||
|         // Find the print object to be processed with priority.
 | ||||
| 		SLAPrintObject *print_object = nullptr; | ||||
| 		size_t          idx_print_object = 0; | ||||
| 		for (; idx_print_object < m_objects.size(); ++ idx_print_object) | ||||
| 			if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) { | ||||
| 				print_object = m_objects[idx_print_object]; | ||||
| 				break; | ||||
| 			} | ||||
| 		assert(print_object != nullptr); | ||||
|         SLAPrintObject *print_object = nullptr; | ||||
|         size_t          idx_print_object = 0; | ||||
|         for (; idx_print_object < m_objects.size(); ++ idx_print_object) | ||||
|             if (m_objects[idx_print_object]->model_object()->id() == params.single_model_object) { | ||||
|                 print_object = m_objects[idx_print_object]; | ||||
|                 break; | ||||
|             } | ||||
|         assert(print_object != nullptr); | ||||
|         // Find out whether the priority print object is being currently processed.
 | ||||
|         bool running = false; | ||||
| 		for (int istep = 0; istep < n_object_steps; ++ istep) { | ||||
| 			if (! print_object->m_stepmask[istep]) | ||||
|         for (int istep = 0; istep < n_object_steps; ++ istep) { | ||||
|             if (! print_object->m_stepmask[istep]) | ||||
|                 // Step was skipped, cancel.
 | ||||
| 				break; | ||||
| 			if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) { | ||||
|                 break; | ||||
|             if (print_object->is_step_started_unguarded(SLAPrintObjectStep(istep))) { | ||||
|                 // No step was skipped, and a wanted step is being processed. Don't cancel.
 | ||||
| 				running = true; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (! running) | ||||
| 			this->call_cancel_callback(); | ||||
|                 running = true; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|         if (! running) | ||||
|             this->call_cancel_callback(); | ||||
| 
 | ||||
| 		// Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
 | ||||
| 		if (params.single_model_instance_only) { | ||||
| 			// Suppress all the steps of other instances.
 | ||||
| 			for (SLAPrintObject *po : m_objects) | ||||
| 				for (int istep = 0; istep < (int)slaposCount; ++ istep) | ||||
| 					po->m_stepmask[istep] = false; | ||||
| 		} else if (! running) { | ||||
| 			// Swap the print objects, so that the selected print_object is first in the row.
 | ||||
| 			// At this point the background processing must be stopped, so it is safe to shuffle print objects.
 | ||||
| 			if (idx_print_object != 0) | ||||
| 				std::swap(m_objects.front(), m_objects[idx_print_object]); | ||||
| 		} | ||||
|         // Now the background process is either stopped, or it is inside one of the print object steps to be calculated anyway.
 | ||||
|         if (params.single_model_instance_only) { | ||||
|             // Suppress all the steps of other instances.
 | ||||
|             for (SLAPrintObject *po : m_objects) | ||||
|                 for (int istep = 0; istep < (int)slaposCount; ++ istep) | ||||
|                     po->m_stepmask[istep] = false; | ||||
|         } else if (! running) { | ||||
|             // Swap the print objects, so that the selected print_object is first in the row.
 | ||||
|             // At this point the background processing must be stopped, so it is safe to shuffle print objects.
 | ||||
|             if (idx_print_object != 0) | ||||
|                 std::swap(m_objects.front(), m_objects[idx_print_object]); | ||||
|         } | ||||
|         // and set the steps for the current object.
 | ||||
| 		for (int istep = 0; istep < n_object_steps; ++ istep) | ||||
| 			print_object->m_stepmask[istep] = true; | ||||
| 		for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep) | ||||
| 			print_object->m_stepmask[istep] = false; | ||||
| 	} else { | ||||
|         for (int istep = 0; istep < n_object_steps; ++ istep) | ||||
|             print_object->m_stepmask[istep] = true; | ||||
|         for (int istep = n_object_steps; istep < (int)slaposCount; ++ istep) | ||||
|             print_object->m_stepmask[istep] = false; | ||||
|     } else { | ||||
|         // Slicing all objects.
 | ||||
|         bool running = false; | ||||
|         for (SLAPrintObject *print_object : m_objects) | ||||
|  | @ -518,9 +525,9 @@ void SLAPrint::set_task(const TaskParams ¶ms) | |||
| 
 | ||||
|     if (params.to_object_step != -1 || params.to_print_step != -1) { | ||||
|         // Limit the print steps.
 | ||||
| 		size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1; | ||||
| 		for (; istep < m_stepmask.size(); ++ istep) | ||||
| 			m_stepmask[istep] = false; | ||||
|         size_t istep = (params.to_object_step != -1) ? 0 : size_t(params.to_print_step) + 1; | ||||
|         for (; istep < m_stepmask.size(); ++ istep) | ||||
|             m_stepmask[istep] = false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | @ -530,7 +537,7 @@ void SLAPrint::finalize() | |||
| { | ||||
|     for (SLAPrintObject *po : m_objects) | ||||
|         for (int istep = 0; istep < (int)slaposCount; ++ istep) | ||||
| 			po->m_stepmask[istep] = true; | ||||
|             po->m_stepmask[istep] = true; | ||||
|     for (int istep = 0; istep < (int)slapsCount; ++ istep) | ||||
|         m_stepmask[istep] = true; | ||||
| } | ||||
|  | @ -539,7 +546,7 @@ void SLAPrint::finalize() | |||
| // (timestamps, object placeholders derived from the model, current placeholder prameters and print statistics.
 | ||||
| // Use the final print statistics if available, or just keep the print statistics placeholders if not available yet (before the output is finalized).
 | ||||
| std::string SLAPrint::output_filename() const | ||||
| {  | ||||
| { | ||||
|     DynamicConfig config = this->finished() ? this->print_statistics().config() : this->print_statistics().placeholders(); | ||||
|     return this->PrintBase::output_filename(m_print_config.output_filename_format.value, "sl1", &config); | ||||
| } | ||||
|  | @ -708,10 +715,17 @@ void SLAPrint::process() | |||
|                      [this](){ throw_if_canceled(); }); | ||||
| 
 | ||||
|         auto mit = slindex_it; | ||||
|         double doffs = m_printer_config.absolute_correction.getFloat(); | ||||
|         coord_t clpr_offs = coord_t(doffs / SCALING_FACTOR); | ||||
|         for(size_t id = 0; | ||||
|             id < po.m_model_slices.size() && mit != po.m_slice_index.end(); | ||||
|             id++) | ||||
|         { | ||||
|             // We apply the printer correction offset here.
 | ||||
|             if(clpr_offs != 0) | ||||
|                 po.m_model_slices[id] =  | ||||
|                         offset_ex(po.m_model_slices[id], clpr_offs); | ||||
|              | ||||
|             mit->set_model_slice_idx(po, id); ++mit; | ||||
|         } | ||||
|     }; | ||||
|  | @ -771,7 +785,7 @@ void SLAPrint::process() | |||
|                                           po.m_supportdata->emesh, | ||||
|                                           po.get_model_slices(), | ||||
|                                           heights, | ||||
|                                           config,  | ||||
|                                           config, | ||||
|                                           [this]() { throw_if_canceled(); }, | ||||
|                                           statuscb); | ||||
| 
 | ||||
|  | @ -913,10 +927,17 @@ void SLAPrint::process() | |||
|                         heights, float(po.config().slice_closing_radius.value)); | ||||
|         } | ||||
| 
 | ||||
|         double doffs = m_printer_config.absolute_correction.getFloat(); | ||||
|         coord_t clpr_offs = coord_t(doffs / SCALING_FACTOR); | ||||
|         for(size_t i = 0; | ||||
|             i < sd->support_slices.size() && i < po.m_slice_index.size(); | ||||
|             ++i) | ||||
|         { | ||||
|             // We apply the printer correction offset here.
 | ||||
|             if(clpr_offs != 0) | ||||
|                 sd->support_slices[i] =  | ||||
|                         offset_ex(sd->support_slices[i], clpr_offs); | ||||
|              | ||||
|             po.m_slice_index[i].set_support_slice_idx(po, i); | ||||
|         } | ||||
| 
 | ||||
|  | @ -1024,6 +1045,8 @@ void SLAPrint::process() | |||
|         const double width              = m_printer_config.display_width.getFloat() / SCALING_FACTOR; | ||||
|         const double height             = m_printer_config.display_height.getFloat() / SCALING_FACTOR; | ||||
|         const double display_area       = width*height; | ||||
|          | ||||
|         const coord_t clpr_back_offs    = - coord_t(m_printer_config.absolute_correction.getFloat() / SCALING_FACTOR); | ||||
| 
 | ||||
|         // get polygons for all instances in the object
 | ||||
|         auto get_all_polygons = | ||||
|  | @ -1107,7 +1130,7 @@ void SLAPrint::process() | |||
|         auto printlayerfn = [this, | ||||
|                 // functions and read only vars
 | ||||
|                 get_all_polygons, polyunion, polydiff, areafn, | ||||
|                 area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, | ||||
|                 area_fill, display_area, exp_time, init_exp_time, fast_tilt, slow_tilt, delta_fade_time, clpr_back_offs, | ||||
| 
 | ||||
|                 // write vars
 | ||||
|                 &mutex, &models_volume, &supports_volume, &estim_time, &slow_layers, | ||||
|  | @ -1143,14 +1166,18 @@ void SLAPrint::process() | |||
|             for(const SliceRecord& record : layer.slices()) { | ||||
|                 const SLAPrintObject *po = record.print_obj(); | ||||
| 
 | ||||
|                 const ExPolygons &modelslices = record.get_slice(soModel); | ||||
|                 const ExPolygons &rawmodelslices = record.get_slice(soModel); | ||||
|                 const ExPolygons &modelslices = clpr_back_offs != 0 ? offset_ex(rawmodelslices, clpr_back_offs) : rawmodelslices; | ||||
|                  | ||||
|                 bool is_lefth = record.print_obj()->is_left_handed(); | ||||
|                 if (!modelslices.empty()) { | ||||
|                     ClipperPolygons v = get_all_polygons(modelslices, po->instances(), is_lefth); | ||||
|                     for(ClipperPolygon& p_tmp : v) model_polygons.emplace_back(std::move(p_tmp)); | ||||
|                 } | ||||
| 
 | ||||
|                 const ExPolygons &supportslices = record.get_slice(soSupport); | ||||
|                 const ExPolygons &rawsupportslices = record.get_slice(soSupport); | ||||
|                 const ExPolygons &supportslices = clpr_back_offs != 0 ? offset_ex(rawsupportslices, clpr_back_offs) : rawsupportslices; | ||||
|                  | ||||
|                 if (!supportslices.empty()) { | ||||
|                     ClipperPolygons v = get_all_polygons(supportslices, po->instances(), is_lefth); | ||||
|                     for(ClipperPolygon& p_tmp : v) supports_polygons.emplace_back(std::move(p_tmp)); | ||||
|  | @ -1259,12 +1286,16 @@ void SLAPrint::process() | |||
|             double lh = ocfg.layer_height.getFloat(); | ||||
|             double exp_t = matcfg.exposure_time.getFloat(); | ||||
|             double iexp_t = matcfg.initial_exposure_time.getFloat(); | ||||
|              | ||||
|             double gamma = m_printer_config.gamma_correction.getFloat(); | ||||
| 
 | ||||
|             if(flpXY) { std::swap(w, h); std::swap(pw, ph); } | ||||
| 
 | ||||
|             m_printer.reset(new SLAPrinter(w, h, pw, ph, lh, exp_t, iexp_t, | ||||
|                                            flpXY? SLAPrinter::RO_PORTRAIT : | ||||
|                                                   SLAPrinter::RO_LANDSCAPE)); | ||||
|             m_printer.reset( | ||||
|                 new SLAPrinter(w, h, pw, ph, lh, exp_t, iexp_t, | ||||
|                                flpXY? SLAPrinter::RO_PORTRAIT :  | ||||
|                                       SLAPrinter::RO_LANDSCAPE,  | ||||
|                                gamma)); | ||||
|         } | ||||
| 
 | ||||
|         // Allocate space for all the layers
 | ||||
|  | @ -1418,24 +1449,29 @@ void SLAPrint::process() | |||
|     m_report_status(*this, 100, L("Slicing done")); | ||||
| } | ||||
| 
 | ||||
| bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys) | ||||
| bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys, bool &invalidate_all_model_objects) | ||||
| { | ||||
|     if (opt_keys.empty()) | ||||
|         return false; | ||||
| 
 | ||||
|     static std::unordered_set<std::string> steps_full = { | ||||
|         "initial_layer_height", | ||||
|         "material_correction", | ||||
|         "relative_correction", | ||||
|         "absolute_correction", | ||||
|         "gamma_correction" | ||||
|     }; | ||||
| 
 | ||||
|     // Cache the plenty of parameters, which influence the final rasterization only,
 | ||||
|     // or they are only notes not influencing the rasterization step.
 | ||||
|     static std::unordered_set<std::string> steps_rasterize = { | ||||
|         "exposure_time", | ||||
|         "initial_exposure_time", | ||||
|         "material_correction_printing", | ||||
|         "material_correction_curing", | ||||
|         "display_width", | ||||
|         "display_height", | ||||
|         "display_pixels_x", | ||||
|         "display_pixels_y", | ||||
|         "display_orientation", | ||||
|         "printer_correction" | ||||
|         "display_orientation" | ||||
|     }; | ||||
| 
 | ||||
|     static std::unordered_set<std::string> steps_ignore = { | ||||
|  | @ -1443,8 +1479,8 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt | |||
|         "max_print_height", | ||||
|         "printer_technology", | ||||
|         "output_filename_format", | ||||
|         "fast_tilt_time",  | ||||
|         "slow_tilt_time",  | ||||
|         "fast_tilt_time", | ||||
|         "slow_tilt_time", | ||||
|         "area_fill" | ||||
|     }; | ||||
| 
 | ||||
|  | @ -1459,9 +1495,10 @@ bool SLAPrint::invalidate_state_by_config_options(const std::vector<t_config_opt | |||
|             steps.emplace_back(slapsMergeSlicesAndEval); | ||||
|         } else if (steps_ignore.find(opt_key) != steps_ignore.end()) { | ||||
|             // These steps have no influence on the output. Just ignore them.
 | ||||
|         } else if (opt_key == "initial_layer_height") { | ||||
|         } else if (steps_full.find(opt_key) != steps_full.end()) { | ||||
|             steps.emplace_back(slapsMergeSlicesAndEval); | ||||
|             osteps.emplace_back(slaposObjectSlice); | ||||
|             invalidate_all_model_objects = true; | ||||
|         } else { | ||||
|             // All values should be covered.
 | ||||
|             assert(false); | ||||
|  | @ -1511,20 +1548,20 @@ bool SLAPrintObject::invalidate_state_by_config_options(const std::vector<t_conf | |||
|     std::vector<SLAPrintObjectStep> steps; | ||||
|     bool invalidated = false; | ||||
|     for (const t_config_option_key &opt_key : opt_keys) { | ||||
| 		if (   opt_key == "layer_height" | ||||
|         if (   opt_key == "layer_height" | ||||
|             || opt_key == "faded_layers" | ||||
|             || opt_key == "pad_enable" | ||||
|             || opt_key == "pad_wall_thickness" | ||||
|             || opt_key == "supports_enable" | ||||
|             || opt_key == "support_object_elevation" | ||||
|             || opt_key == "slice_closing_radius") { | ||||
| 			steps.emplace_back(slaposObjectSlice); | ||||
|             steps.emplace_back(slaposObjectSlice); | ||||
|         } else if ( | ||||
| 
 | ||||
|                opt_key == "support_points_density_relative" | ||||
|             || opt_key == "support_points_minimal_distance") { | ||||
|             steps.emplace_back(slaposSupportPoints); | ||||
| 		} else if ( | ||||
|         } else if ( | ||||
|                opt_key == "support_head_front_diameter" | ||||
|             || opt_key == "support_head_penetration" | ||||
|             || opt_key == "support_head_width" | ||||
|  | @ -1613,6 +1650,25 @@ double SLAPrintObject::get_current_elevation() const | |||
|     return get_elevation(); | ||||
| } | ||||
| 
 | ||||
| Vec3d SLAPrint::relative_correction() const | ||||
| { | ||||
|     Vec3d corr(1., 1., 1.); | ||||
| 
 | ||||
|     if(printer_config().relative_correction.values.size() == 2) { | ||||
|         corr(X) = printer_config().relative_correction.values[0]; | ||||
|         corr(Y) = printer_config().relative_correction.values[0]; | ||||
|         corr(Z) = printer_config().relative_correction.values[1]; | ||||
|     } | ||||
| 
 | ||||
|     if(material_config().material_correction.values.size() == 2) { | ||||
|         corr(X) *= material_config().material_correction.values[0]; | ||||
|         corr(Y) *= material_config().material_correction.values[0]; | ||||
|         corr(Z) *= material_config().material_correction.values[1]; | ||||
|     } | ||||
| 
 | ||||
|     return corr; | ||||
| } | ||||
| 
 | ||||
| namespace { // dummy empty static containers for return values in some methods
 | ||||
| const std::vector<ExPolygons> EMPTY_SLICES; | ||||
| const TriangleMesh EMPTY_MESH; | ||||
|  |  | |||
|  | @ -397,7 +397,10 @@ public: | |||
|     const SLAMaterialConfig&    material_config() const { return m_material_config; } | ||||
|     const SLAPrintObjectConfig& default_object_config() const { return m_default_object_config; } | ||||
| 
 | ||||
| 	std::string         output_filename() const override; | ||||
|     // Extracted value from the configuration objects
 | ||||
|     Vec3d                       relative_correction() const; | ||||
| 
 | ||||
| 	std::string                 output_filename() const override; | ||||
| 
 | ||||
|     const SLAPrintStatistics&      print_statistics() const { return m_print_statistics; } | ||||
| 
 | ||||
|  | @ -452,7 +455,7 @@ private: | |||
|     bool invalidate_step(SLAPrintStep st); | ||||
| 
 | ||||
|     // Invalidate steps based on a set of parameters changed.
 | ||||
|     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys); | ||||
|     bool invalidate_state_by_config_options(const std::vector<t_config_option_key> &opt_keys, bool &invalidate_all_model_objects); | ||||
| 
 | ||||
|     SLAPrintConfig                  m_print_config; | ||||
|     SLAPrinterConfig                m_printer_config; | ||||
|  |  | |||
|  | @ -18,10 +18,10 @@ wxPanel(parent, wxID_ANY, wxDefaultPosition, wxSize(25 * wxGetApp().em_unit(), - | |||
| #ifdef __APPLE__ | ||||
|     m_user_drawn_background = false; | ||||
| #endif /*__APPLE__*/ | ||||
|     Bind(wxEVT_PAINT, ([this](wxPaintEvent e) { repaint(); })); | ||||
|     Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent  event) { mouse_event(event); })); | ||||
|     Bind(wxEVT_MOTION, ([this](wxMouseEvent  event) { mouse_event(event); })); | ||||
|     Bind(wxEVT_SIZE, ([this](wxSizeEvent e) { Refresh(); })); | ||||
|     Bind(wxEVT_PAINT, ([this](wxPaintEvent &/* e */) { repaint(); })); | ||||
|     Bind(wxEVT_LEFT_DOWN, ([this](wxMouseEvent &event) { mouse_event(event); })); | ||||
|     Bind(wxEVT_MOTION, ([this](wxMouseEvent &event) { mouse_event(event); })); | ||||
|     Bind(wxEVT_SIZE, ([this](wxSizeEvent & /* e */) { Refresh(); })); | ||||
| } | ||||
| void Bed_2D::repaint() | ||||
| { | ||||
|  |  | |||
|  | @ -227,6 +227,12 @@ const float GLVolume::HOVER_COLOR[4] = { 0.4f, 0.9f, 0.1f, 1.0f }; | |||
| const float GLVolume::OUTSIDE_COLOR[4] = { 0.0f, 0.38f, 0.8f, 1.0f }; | ||||
| const float GLVolume::SELECTED_OUTSIDE_COLOR[4] = { 0.19f, 0.58f, 1.0f, 1.0f }; | ||||
| const float GLVolume::DISABLED_COLOR[4] = { 0.25f, 0.25f, 0.25f, 1.0f }; | ||||
| const float GLVolume::MODEL_COLOR[4][4] = { | ||||
|     { 1.0f, 1.0f, 0.0f, 1.f }, | ||||
|     { 1.0f, 0.5f, 0.5f, 1.f }, | ||||
|     { 0.5f, 1.0f, 0.5f, 1.f }, | ||||
|     { 0.5f, 0.5f, 1.0f, 1.f } | ||||
| }; | ||||
| const float GLVolume::SLA_SUPPORT_COLOR[4] = { 0.75f, 0.75f, 0.75f, 1.0f }; | ||||
| const float GLVolume::SLA_PAD_COLOR[4] = { 0.0f, 0.2f, 0.0f, 1.0f }; | ||||
| 
 | ||||
|  | @ -568,19 +574,12 @@ int GLVolumeCollection::load_object_volume( | |||
|     const std::string              &color_by, | ||||
|     bool                            use_VBOs) | ||||
| { | ||||
|     static float colors[4][4] = { | ||||
|         { 1.0f, 1.0f, 0.0f, 1.f },  | ||||
|         { 1.0f, 0.5f, 0.5f, 1.f }, | ||||
|         { 0.5f, 1.0f, 0.5f, 1.f },  | ||||
|         { 0.5f, 0.5f, 1.0f, 1.f } | ||||
|     }; | ||||
| 
 | ||||
|     const ModelVolume   *model_volume = model_object->volumes[volume_idx]; | ||||
|     const int            extruder_id  = model_volume->extruder_id(); | ||||
|     const ModelInstance *instance     = model_object->instances[instance_idx]; | ||||
|     const TriangleMesh& mesh = model_volume->mesh; | ||||
|     float color[4]; | ||||
|     memcpy(color, colors[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); | ||||
|     memcpy(color, GLVolume::MODEL_COLOR[((color_by == "volume") ? volume_idx : obj_idx) % 4], sizeof(float) * 3); | ||||
| /*    if (model_volume->is_support_blocker()) {
 | ||||
|         color[0] = 1.0f; | ||||
|         color[1] = 0.2f; | ||||
|  | @ -595,10 +594,7 @@ int GLVolumeCollection::load_object_volume( | |||
|     this->volumes.emplace_back(new GLVolume(color)); | ||||
|     GLVolume &v = *this->volumes.back(); | ||||
|     v.set_color_from_model_volume(model_volume); | ||||
|     if (use_VBOs) | ||||
|         v.indexed_vertex_array.load_mesh_full_shading(mesh); | ||||
|     else | ||||
|         v.indexed_vertex_array.load_mesh_flat_shading(mesh); | ||||
|     v.indexed_vertex_array.load_mesh(mesh, use_VBOs); | ||||
| 
 | ||||
|     // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
 | ||||
|     v.bounding_box = v.indexed_vertex_array.bounding_box(); | ||||
|  | @ -640,14 +636,10 @@ void GLVolumeCollection::load_object_auxiliary( | |||
| 	// Convex hull is required for out of print bed detection.
 | ||||
| 	TriangleMesh convex_hull = mesh.convex_hull_3d(); | ||||
|     for (const std::pair<size_t, size_t> &instance_idx : instances) { | ||||
|         const ModelInstance            &model_instance = *print_object->model_object()->instances[instance_idx.first]; | ||||
|         const SLAPrintObject::Instance &print_instance = print_object->instances()[instance_idx.second]; | ||||
|         const ModelInstance &model_instance = *print_object->model_object()->instances[instance_idx.first]; | ||||
|         this->volumes.emplace_back(new GLVolume((milestone == slaposBasePool) ? GLVolume::SLA_PAD_COLOR : GLVolume::SLA_SUPPORT_COLOR)); | ||||
|         GLVolume &v = *this->volumes.back(); | ||||
|         if (use_VBOs) | ||||
|             v.indexed_vertex_array.load_mesh_full_shading(mesh); | ||||
|         else | ||||
|             v.indexed_vertex_array.load_mesh_flat_shading(mesh); | ||||
|         v.indexed_vertex_array.load_mesh(mesh, use_VBOs); | ||||
|         // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
 | ||||
|         v.bounding_box = v.indexed_vertex_array.bounding_box(); | ||||
|         v.indexed_vertex_array.finalize_geometry(use_VBOs); | ||||
|  | @ -718,14 +710,8 @@ int GLVolumeCollection::load_wipe_tower_preview( | |||
| 
 | ||||
|     this->volumes.emplace_back(new GLVolume(color)); | ||||
|     GLVolume &v = *this->volumes.back(); | ||||
| 
 | ||||
|     if (use_VBOs) | ||||
|         v.indexed_vertex_array.load_mesh_full_shading(mesh); | ||||
|     else | ||||
|         v.indexed_vertex_array.load_mesh_flat_shading(mesh); | ||||
| 
 | ||||
|     v.indexed_vertex_array.load_mesh(mesh, use_VBOs); | ||||
|     v.set_volume_offset(Vec3d(pos_x, pos_y, 0.0)); | ||||
| 
 | ||||
|     // finalize_geometry() clears the vertex arrays, therefore the bounding box has to be computed before finalize_geometry().
 | ||||
|     v.bounding_box = v.indexed_vertex_array.bounding_box(); | ||||
|     v.indexed_vertex_array.finalize_geometry(use_VBOs); | ||||
|  | @ -1856,12 +1842,7 @@ bool GLArrow::on_init(bool useVBOs) | |||
|     triangles.emplace_back(7, 13, 6); | ||||
| 
 | ||||
|     m_useVBOs = useVBOs; | ||||
| 
 | ||||
|     if (m_useVBOs) | ||||
|         m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles)); | ||||
|     else | ||||
|         m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles)); | ||||
| 
 | ||||
| 	m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles), useVBOs); | ||||
|     m_volume.finalize_geometry(m_useVBOs); | ||||
|     return true; | ||||
| } | ||||
|  | @ -1976,12 +1957,7 @@ bool GLCurvedArrow::on_init(bool useVBOs) | |||
|     triangles.emplace_back(vertices_per_level, 2 * vertices_per_level + 1, vertices_per_level + 1); | ||||
| 
 | ||||
|     m_useVBOs = useVBOs; | ||||
| 
 | ||||
|     if (m_useVBOs) | ||||
|         m_volume.indexed_vertex_array.load_mesh_full_shading(TriangleMesh(vertices, triangles)); | ||||
|     else | ||||
|         m_volume.indexed_vertex_array.load_mesh_flat_shading(TriangleMesh(vertices, triangles)); | ||||
| 
 | ||||
| 	m_volume.indexed_vertex_array.load_mesh(TriangleMesh(vertices, triangles), useVBOs); | ||||
|     m_volume.bounding_box = m_volume.indexed_vertex_array.bounding_box(); | ||||
|     m_volume.finalize_geometry(m_useVBOs); | ||||
|     return true; | ||||
|  | @ -2016,10 +1992,7 @@ bool GLBed::on_init_from_file(const std::string& filename, bool useVBOs) | |||
|     TriangleMesh mesh = model.mesh(); | ||||
|     mesh.repair(); | ||||
| 
 | ||||
|     if (m_useVBOs) | ||||
|         m_volume.indexed_vertex_array.load_mesh_full_shading(mesh); | ||||
|     else | ||||
|         m_volume.indexed_vertex_array.load_mesh_flat_shading(mesh); | ||||
| 	m_volume.indexed_vertex_array.load_mesh(mesh, useVBOs); | ||||
| 
 | ||||
|     float color[4] = { 0.235f, 0.235f, 0.235f, 1.0f }; | ||||
|     set_color(color, 4); | ||||
|  |  | |||
|  | @ -116,6 +116,7 @@ public: | |||
| 
 | ||||
|     void load_mesh_flat_shading(const TriangleMesh &mesh); | ||||
|     void load_mesh_full_shading(const TriangleMesh &mesh); | ||||
| 	void load_mesh(const TriangleMesh &mesh, bool use_VBOs) { use_VBOs ? this->load_mesh_full_shading(mesh) : this->load_mesh_flat_shading(mesh); } | ||||
| 
 | ||||
|     inline bool has_VBOs() const { return vertices_and_normals_interleaved_VBO_id != 0; } | ||||
| 
 | ||||
|  | @ -228,6 +229,7 @@ public: | |||
|     static const float OUTSIDE_COLOR[4]; | ||||
|     static const float SELECTED_OUTSIDE_COLOR[4]; | ||||
|     static const float DISABLED_COLOR[4]; | ||||
|     static const float MODEL_COLOR[4][4]; | ||||
|     static const float SLA_SUPPORT_COLOR[4]; | ||||
|     static const float SLA_PAD_COLOR[4]; | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ AboutDialog::AboutDialog() | |||
| 	main_sizer->Add(hsizer, 0, wxEXPAND | wxALL, 20); | ||||
| 
 | ||||
|     // logo
 | ||||
| 	auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png", 192)); | ||||
|     auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap(this, "Slic3r_192px.png", 192)); | ||||
| 	hsizer->Add(logo, 1, wxALIGN_CENTER_VERTICAL); | ||||
|      | ||||
|     wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); 	 | ||||
|  |  | |||
|  | @ -27,16 +27,25 @@ void BitmapCache::clear() | |||
|     m_map.clear(); | ||||
| } | ||||
| 
 | ||||
| static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image) | ||||
| static wxBitmap wxImage_to_wxBitmap_with_alpha(wxImage &&image, float scale = 1.0f) | ||||
| { | ||||
| #ifdef BROKEN_ALPHA | ||||
|     wxMemoryOutputStream stream; | ||||
|     image.SaveFile(stream, wxBITMAP_TYPE_PNG); | ||||
|     wxStreamBuffer *buf = stream.GetOutputStreamBuffer(); | ||||
|     return wxBitmap::NewFromPNGData(buf->GetBufferStart(), buf->GetBufferSize()); | ||||
| #else | ||||
| #ifdef __APPLE__ | ||||
|     // This is a c-tor native to Mac OS. We need to let the Mac OS wxBitmap implementation
 | ||||
|     // know that the image may already be scaled appropriately for Retina,
 | ||||
|     // and thereby that it's not supposed to upscale it.
 | ||||
|     // Contrary to intuition, the `scale` argument isn't "please scale this to such and such"
 | ||||
|     // but rather "the wxImage is sized for backing scale such and such".
 | ||||
|     return wxBitmap(std::move(image), -1, scale); | ||||
| #else | ||||
|     return wxBitmap(std::move(image)); | ||||
| #endif | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::insert(const std::string &bitmap_key, size_t width, size_t height) | ||||
|  | @ -165,7 +174,7 @@ wxBitmap* BitmapCache::insert(const std::string &bitmap_key, const wxBitmap *beg | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data) | ||||
| wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale /* = 1.0f */) | ||||
| { | ||||
|     wxImage image(width, height); | ||||
|     image.InitAlpha(); | ||||
|  | @ -178,7 +187,7 @@ wxBitmap* BitmapCache::insert_raw_rgba(const std::string &bitmap_key, unsigned i | |||
|         *rgb   ++ = *raw_data ++; | ||||
|         *alpha ++ = *raw_data ++; | ||||
|     } | ||||
|     return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); | ||||
|     return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image), scale)); | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int width, unsigned int height) | ||||
|  | @ -186,6 +195,7 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int wid | |||
|     std::string bitmap_key = bitmap_name + ( height !=0 ?  | ||||
|                                            "-h" + std::to_string(height) :  | ||||
|                                            "-w" + std::to_string(width)); | ||||
| 
 | ||||
|     auto it = m_map.find(bitmap_key); | ||||
|     if (it != m_map.end()) | ||||
|         return it->second; | ||||
|  | @ -206,11 +216,15 @@ wxBitmap* BitmapCache::load_png(const std::string &bitmap_name, unsigned int wid | |||
|     return this->insert(bitmap_key, wxImage_to_wxBitmap_with_alpha(std::move(image))); | ||||
| } | ||||
| 
 | ||||
| wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int target_width, unsigned int target_height) | ||||
| wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned target_width, unsigned target_height, float scale /* = 1.0f */) | ||||
| { | ||||
|     std::string bitmap_key = bitmap_name + (target_height != 0 ? | ||||
|                                             "-h" + std::to_string(target_height) : | ||||
|                                             "-w" + std::to_string(target_width)); | ||||
|     std::string bitmap_key = bitmap_name + ( target_height !=0 ?  | ||||
|                                            "-h" + std::to_string(target_height) :  | ||||
|                                            "-w" + std::to_string(target_width)) | ||||
|                                          + (scale != 1.0f ? "-s" + std::to_string(scale) : ""); | ||||
| 
 | ||||
|     target_height != 0 ? target_height *= scale : target_width *= scale; | ||||
| 
 | ||||
|     auto it = m_map.find(bitmap_key); | ||||
|     if (it != m_map.end()) | ||||
|         return it->second; | ||||
|  | @ -219,12 +233,12 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int tar | |||
|     if (image == nullptr) | ||||
|         return nullptr; | ||||
| 
 | ||||
|     float scale = target_height != 0 ?  | ||||
|     float svg_scale = target_height != 0 ?  | ||||
|                   (float)target_height / image->height  : target_width != 0 ? | ||||
|                   (float)target_width / image->width    : 1; | ||||
| 
 | ||||
|     int   width    = (int)(scale * image->width + 0.5f); | ||||
|     int   height   = (int)(scale * image->height + 0.5f); | ||||
|     int   width    = (int)(svg_scale * image->width + 0.5f); | ||||
|     int   height   = (int)(svg_scale * image->height + 0.5f); | ||||
|     int   n_pixels = width * height; | ||||
|     if (n_pixels <= 0) { | ||||
|         ::nsvgDelete(image); | ||||
|  | @ -238,11 +252,11 @@ wxBitmap* BitmapCache::load_svg(const std::string &bitmap_name, unsigned int tar | |||
|     } | ||||
| 
 | ||||
|     std::vector<unsigned char> data(n_pixels * 4, 0); | ||||
|     ::nsvgRasterize(rast, image, 0, 0, scale, data.data(), width, height, width * 4); | ||||
|     ::nsvgRasterize(rast, image, 0, 0, svg_scale, data.data(), width, height, width * 4); | ||||
|     ::nsvgDeleteRasterizer(rast); | ||||
|     ::nsvgDelete(image); | ||||
| 
 | ||||
|     return this->insert_raw_rgba(bitmap_key, width, height, data.data()); | ||||
|     return this->insert_raw_rgba(bitmap_key, width, height, data.data(), scale); | ||||
| } | ||||
| 
 | ||||
| wxBitmap BitmapCache::mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency) | ||||
|  |  | |||
|  | @ -29,12 +29,12 @@ public: | |||
| 	wxBitmap* 		insert(const std::string &name, const wxBitmap &bmp, const wxBitmap &bmp2, const wxBitmap &bmp3); | ||||
| 	wxBitmap* 		insert(const std::string &name, const std::vector<wxBitmap> &bmps) { return this->insert(name, &bmps.front(), &bmps.front() + bmps.size()); } | ||||
| 	wxBitmap* 		insert(const std::string &name, const wxBitmap *begin, const wxBitmap *end); | ||||
| 	wxBitmap* 		insert_raw_rgba(const std::string &bitmap_key, unsigned int width, unsigned int height, const unsigned char *raw_data); | ||||
| 	wxBitmap* 		insert_raw_rgba(const std::string &bitmap_key, unsigned width, unsigned height, const unsigned char *raw_data, float scale = 1.0f); | ||||
| 
 | ||||
| 	// Load png from resources/icons. bitmap_key is given without the .png suffix. Bitmap will be rescaled to provided height/width if nonzero.
 | ||||
| 	wxBitmap* 		load_png(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0); | ||||
| 	// Load svg from resources/icons. bitmap_key is given without the .svg suffix. SVG will be rasterized to provided height/width.
 | ||||
|     wxBitmap* 		load_svg(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0); | ||||
|     wxBitmap* 		load_svg(const std::string &bitmap_key, unsigned int width = 0, unsigned int height = 0, float scale = 1.0f); | ||||
| 
 | ||||
| 	static wxBitmap mksolid(size_t width, size_t height, unsigned char r, unsigned char g, unsigned char b, unsigned char transparency); | ||||
| 	static wxBitmap mksolid(size_t width, size_t height, const unsigned char rgb[3]) { return mksolid(width, height, rgb[0], rgb[1], rgb[2], wxALPHA_OPAQUE); } | ||||
|  |  | |||
|  | @ -1893,6 +1893,9 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re | |||
|             size_t idx = 0; | ||||
|             const SLAPrint *sla_print = this->sla_print(); | ||||
| 			std::vector<double> shift_zs(m_model->objects.size(), 0); | ||||
|             double relative_correction_z = sla_print->relative_correction().z(); | ||||
|             if (relative_correction_z <= EPSILON) | ||||
|                 relative_correction_z = 1.; | ||||
| 			for (const SLAPrintObject *print_object : sla_print->objects()) { | ||||
|                 SLASupportState   &state        = sla_support_state[idx ++]; | ||||
|                 const ModelObject *model_object = print_object->model_object(); | ||||
|  | @ -1906,7 +1909,7 @@ void GLCanvas3D::reload_scene(bool refresh_immediately, bool force_full_scene_re | |||
|                 assert(it != sla_print->model().objects.end()); | ||||
| 				object_idx = it - sla_print->model().objects.begin(); | ||||
| 				// Cache the Z offset to be applied to all volumes with this object_idx.
 | ||||
| 				shift_zs[object_idx] = print_object->get_current_elevation(); | ||||
| 				shift_zs[object_idx] = print_object->get_current_elevation() / relative_correction_z; | ||||
|                 // Collect indices of this print_object's instances, for which the SLA support meshes are to be added to the scene.
 | ||||
|                 // pairs of <instance_idx, print_instance_idx>
 | ||||
| 				std::vector<std::pair<size_t, size_t>> instances[std::tuple_size<SLASteps>::value]; | ||||
|  | @ -2310,6 +2313,9 @@ void GLCanvas3D::on_key(wxKeyEvent& evt) | |||
| 
 | ||||
| void GLCanvas3D::on_mouse_wheel(wxMouseEvent& evt) | ||||
| { | ||||
|     if (!m_initialized) | ||||
|         return; | ||||
| 
 | ||||
|     // Ignore the wheel events if the middle button is pressed.
 | ||||
|     if (evt.MiddleIsDown()) | ||||
|         return; | ||||
|  | @ -2563,8 +2569,7 @@ void GLCanvas3D::on_mouse(wxMouseEvent& evt) | |||
|                         m_selection.remove(m_hover_volume_id); | ||||
|                     else | ||||
|                     { | ||||
|                         bool add_as_single = !already_selected && !ctrl_down; | ||||
|                         m_selection.add(m_hover_volume_id, add_as_single); | ||||
|                         m_selection.add(m_hover_volume_id, !ctrl_down); | ||||
|                         m_mouse.drag.move_requires_threshold = !already_selected; | ||||
|                         if (already_selected) | ||||
|                             m_mouse.set_move_start_threshold_position_2D_as_invalid(); | ||||
|  | @ -3293,8 +3298,9 @@ bool GLCanvas3D::_init_toolbar() | |||
| 
 | ||||
| bool GLCanvas3D::_set_current() | ||||
| { | ||||
|     if ((m_canvas != nullptr) && (m_context != nullptr)) | ||||
|     if (_is_shown_on_screen() && (m_context != nullptr)) { | ||||
|         return m_canvas->SetCurrent(*m_context); | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
|  | @ -5038,97 +5044,44 @@ void GLCanvas3D::_load_shells_sla() | |||
|         // nothing to render, return
 | ||||
|         return; | ||||
| 
 | ||||
|     auto add_volume = [this](const SLAPrintObject &object, const SLAPrintObject::Instance& instance,  | ||||
|                              const TriangleMesh &mesh, const float color[4], bool outside_printer_detection_enabled) { | ||||
|         m_volumes.volumes.emplace_back(new GLVolume(color)); | ||||
|         GLVolume& v = *m_volumes.volumes.back(); | ||||
|         v.indexed_vertex_array.load_mesh(mesh, m_use_VBOs); | ||||
| 		v.shader_outside_printer_detection_enabled = outside_printer_detection_enabled; | ||||
|         v.composite_id.volume_id = -1; | ||||
|         v.set_instance_offset(unscale(instance.shift(0), instance.shift(1), 0)); | ||||
|         v.set_instance_rotation(Vec3d(0.0, 0.0, (double)instance.rotation)); | ||||
|         v.set_instance_mirror(X, object.is_left_handed() ? -1. : 1.); | ||||
|     }; | ||||
| 
 | ||||
|     // adds objects' volumes 
 | ||||
|     int obj_idx = 0; | ||||
|     for (const SLAPrintObject* obj : print->objects()) | ||||
|     { | ||||
|         if (!obj->is_step_done(slaposSliceSupports)) | ||||
|             continue; | ||||
| 
 | ||||
|         unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); | ||||
| 
 | ||||
|         // selects only instances which were sliced
 | ||||
|         const ModelObject* model_obj = obj->model_object(); | ||||
|         const std::vector<SLAPrintObject::Instance>& sla_instances = obj->instances(); | ||||
|         std::vector<int> instances_model_idxs(sla_instances.size()); | ||||
|         for (int i = 0; i < (int)sla_instances.size(); ++i) | ||||
|         { | ||||
|             instances_model_idxs[i] = (int)sla_instances[i].instance_id.id; | ||||
|         } | ||||
| 
 | ||||
|         std::vector<int> sliced_instance_idxs; | ||||
|         for (int i = 0; i < (int)model_obj->instances.size(); ++i) | ||||
|         { | ||||
|             if (std::find(instances_model_idxs.begin(), instances_model_idxs.end(), (int)model_obj->instances[i]->id().id) != instances_model_idxs.end()) | ||||
|                 sliced_instance_idxs.push_back(i); | ||||
|         } | ||||
| 
 | ||||
|         m_volumes.load_object(model_obj, obj_idx, sliced_instance_idxs, "object", m_use_VBOs && m_initialized); | ||||
| 
 | ||||
|         for (const SLAPrintObject::Instance& instance : sla_instances) | ||||
|         { | ||||
|             Vec3d offset = unscale(instance.shift(0), instance.shift(1), 0); | ||||
|             Vec3d rotation(0.0, 0.0, (double)instance.rotation); | ||||
| 
 | ||||
|             unsigned int partial_volumes_count = (unsigned int)m_volumes.volumes.size(); | ||||
| 
 | ||||
|             // add supports
 | ||||
|             if (obj->is_step_done(slaposSupportTree) && obj->has_mesh(slaposSupportTree)) | ||||
|             { | ||||
|                 const TriangleMesh& mesh = obj->support_mesh(); | ||||
|                 m_volumes.volumes.emplace_back(new GLVolume(GLVolume::SLA_SUPPORT_COLOR)); | ||||
|                 GLVolume& v = *m_volumes.volumes.back(); | ||||
| 
 | ||||
|                 if (m_use_VBOs) | ||||
|                     v.indexed_vertex_array.load_mesh_full_shading(mesh); | ||||
|                 else | ||||
|                     v.indexed_vertex_array.load_mesh_flat_shading(mesh); | ||||
| 
 | ||||
|                 v.shader_outside_printer_detection_enabled = true; | ||||
|                 v.composite_id.volume_id = -1; | ||||
|                 v.set_instance_offset(offset); | ||||
|                 v.set_instance_rotation(rotation); | ||||
|                 v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.); | ||||
|         if (obj->is_step_done(slaposSliceSupports)) { | ||||
|             unsigned int initial_volumes_count = (unsigned int)m_volumes.volumes.size(); | ||||
|             for (const SLAPrintObject::Instance& instance : obj->instances()) { | ||||
|                 add_volume(*obj, instance, obj->transformed_mesh(), GLVolume::MODEL_COLOR[0], true); | ||||
|                 // Set the extruder_id and volume_id to achieve the same color as in the 3D scene when
 | ||||
|                 // through the update_volumes_colors_by_extruder() call.
 | ||||
|                 m_volumes.volumes.back()->extruder_id = obj->model_object()->volumes.front()->extruder_id(); | ||||
|                 m_volumes.volumes.back()->composite_id.volume_id = 0; | ||||
|                 if (obj->is_step_done(slaposSupportTree) && obj->has_mesh(slaposSupportTree)) | ||||
|                     add_volume(*obj, instance, obj->support_mesh(), GLVolume::SLA_SUPPORT_COLOR, true); | ||||
|                 if (obj->is_step_done(slaposBasePool) && obj->has_mesh(slaposBasePool)) | ||||
|                     add_volume(*obj, instance, obj->pad_mesh(), GLVolume::SLA_PAD_COLOR, true); | ||||
|             } | ||||
| 
 | ||||
|             // add pad
 | ||||
|             if (obj->is_step_done(slaposBasePool) && obj->has_mesh(slaposBasePool)) | ||||
|             { | ||||
|                 const TriangleMesh& mesh = obj->pad_mesh(); | ||||
|                 m_volumes.volumes.emplace_back(new GLVolume(GLVolume::SLA_PAD_COLOR)); | ||||
|                 GLVolume& v = *m_volumes.volumes.back(); | ||||
| 
 | ||||
|                 if (m_use_VBOs) | ||||
|                     v.indexed_vertex_array.load_mesh_full_shading(mesh); | ||||
|                 else | ||||
|                     v.indexed_vertex_array.load_mesh_flat_shading(mesh); | ||||
| 
 | ||||
|                 v.shader_outside_printer_detection_enabled = false; | ||||
|                 v.composite_id.volume_id = -1; | ||||
|                 v.set_instance_offset(offset); | ||||
|                 v.set_instance_rotation(rotation); | ||||
|                 v.set_instance_mirror(X, obj->is_left_handed() ? -1. : 1.); | ||||
|             } | ||||
| 
 | ||||
|             // finalize volumes and sends geometry to gpu
 | ||||
|             for (unsigned int i = partial_volumes_count; i < m_volumes.volumes.size(); ++i) | ||||
|             { | ||||
|             double shift_z = obj->get_current_elevation(); | ||||
|             for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++ i) { | ||||
|                 GLVolume& v = *m_volumes.volumes[i]; | ||||
|                 // finalize volumes and sends geometry to gpu
 | ||||
|                 v.bounding_box = v.indexed_vertex_array.bounding_box(); | ||||
|                 v.indexed_vertex_array.finalize_geometry(m_use_VBOs); | ||||
|                 // apply shift z
 | ||||
|                 v.set_sla_shift_z(shift_z); | ||||
|             } | ||||
| 
 | ||||
|             ++obj_idx; | ||||
|         } | ||||
| 
 | ||||
|         // apply shift z
 | ||||
|         double shift_z = obj->get_current_elevation(); | ||||
|         for (unsigned int i = initial_volumes_count; i < m_volumes.volumes.size(); ++i) | ||||
|         { | ||||
|             m_volumes.volumes[i]->set_sla_shift_z(shift_z); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     update_volumes_colors_by_extruder(); | ||||
| #else | ||||
|     this->reload_scene(true, true); | ||||
|  |  | |||
|  | @ -19,6 +19,8 @@ | |||
| #include <wx/wupdlock.h> | ||||
| #include <wx/filefn.h> | ||||
| #include <wx/sysopt.h> | ||||
| #include <wx/msgdlg.h> | ||||
| #include <wx/log.h> | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "libslic3r/Model.hpp" | ||||
|  | @ -94,6 +96,34 @@ static void register_dpi_event() | |||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void generic_exception_handle() | ||||
| { | ||||
|     // Note: Some wxWidgets APIs use wxLogError() to report errors, eg. wxImage
 | ||||
|     // - see https://docs.wxwidgets.org/3.1/classwx_image.html#aa249e657259fe6518d68a5208b9043d0
 | ||||
|     //
 | ||||
|     // wxLogError typically goes around exception handling and display an error dialog some time
 | ||||
|     // after an error is logged even if exception handling and OnExceptionInMainLoop() take place.
 | ||||
|     // This is why we use wxLogError() here as well instead of a custom dialog, because it accumulates
 | ||||
|     // errors if multiple have been collected and displays just one error message for all of them.
 | ||||
|     // Otherwise we would get multiple error messages for one missing png, for example.
 | ||||
|     //
 | ||||
|     // If a custom error message window (or some other solution) were to be used, it would be necessary
 | ||||
|     // to turn off wxLogError() usage in wx APIs, most notably in wxImage
 | ||||
|     // - see https://docs.wxwidgets.org/trunk/classwx_image.html#aa32e5d3507cc0f8c3330135bc0befc6a
 | ||||
| 
 | ||||
|     try { | ||||
|         throw; | ||||
|     } catch (const std::exception &ex) { | ||||
|         wxLogError("Internal error: %s", ex.what()); | ||||
|         BOOST_LOG_TRIVIAL(error) << boost::format("Uncaught exception: %1%") % ex.what(); | ||||
|         throw; | ||||
|     } catch (...) { | ||||
|         wxLogError("Unknown internal error"); | ||||
|         BOOST_LOG_TRIVIAL(error) << "Uncaught exception: Unknown error"; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| IMPLEMENT_APP(GUI_App) | ||||
| 
 | ||||
| GUI_App::GUI_App() | ||||
|  | @ -103,6 +133,16 @@ GUI_App::GUI_App() | |||
| {} | ||||
| 
 | ||||
| bool GUI_App::OnInit() | ||||
| { | ||||
|     try { | ||||
|         return on_init_inner(); | ||||
|     } catch (...) { | ||||
|         generic_exception_handle(); | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool GUI_App::on_init_inner() | ||||
| { | ||||
|     // Verify resources path
 | ||||
|     const wxString resources_dir = from_u8(Slic3r::resources_dir()); | ||||
|  | @ -132,13 +172,7 @@ bool GUI_App::OnInit() | |||
| 
 | ||||
|     // just checking for existence of Slic3r::data_dir is not enough : it may be an empty directory
 | ||||
|     // supplied as argument to --datadir; in that case we should still run the wizard
 | ||||
|     try {  | ||||
|         preset_bundle->setup_directories(); | ||||
|     } catch (const std::exception &ex) { | ||||
|         show_error(nullptr, ex.what()); | ||||
|         // Exit the application.
 | ||||
|         return false; | ||||
|     } | ||||
|     preset_bundle->setup_directories(); | ||||
| 
 | ||||
|     app_conf_exists = app_config->exists(); | ||||
|     // load settings
 | ||||
|  | @ -161,11 +195,11 @@ bool GUI_App::OnInit() | |||
| 
 | ||||
|     // Suppress the '- default -' presets.
 | ||||
|     preset_bundle->set_default_suppressed(app_config->get("no_defaults") == "1"); | ||||
| 	try { | ||||
| 		preset_bundle->load_presets(*app_config); | ||||
| 	} catch (const std::exception &ex) { | ||||
|         show_error(nullptr, ex.what()); | ||||
| 	} | ||||
|     try { | ||||
|         preset_bundle->load_presets(*app_config); | ||||
|     } catch (const std::exception &ex) { | ||||
|         show_error(nullptr, from_u8(ex.what())); | ||||
|     } | ||||
| 
 | ||||
|     register_dpi_event(); | ||||
| 
 | ||||
|  | @ -184,8 +218,8 @@ bool GUI_App::OnInit() | |||
| 
 | ||||
|     Bind(wxEVT_IDLE, [this](wxIdleEvent& event) | ||||
|     { | ||||
| 		if (! plater_) | ||||
| 			return; | ||||
|         if (! plater_) | ||||
|             return; | ||||
| 
 | ||||
|         if (app_config->dirty() && app_config->get("autosave") == "1") | ||||
|             app_config->save(); | ||||
|  | @ -207,7 +241,7 @@ bool GUI_App::OnInit() | |||
|                     mainframe->Close(); | ||||
|                 } | ||||
|             } catch (const std::exception &ex) { | ||||
|                 show_error(nullptr, ex.what()); | ||||
|                 show_error(nullptr, from_u8(ex.what())); | ||||
|             } | ||||
| 
 | ||||
|             CallAfter([this] { | ||||
|  | @ -752,18 +786,7 @@ void GUI_App::load_current_presets() | |||
| 
 | ||||
| bool GUI_App::OnExceptionInMainLoop() | ||||
| { | ||||
|     try { | ||||
|         throw; | ||||
|     } catch (const std::exception &ex) { | ||||
|         const std::string error = (boost::format("Uncaught exception: %1%") % ex.what()).str(); | ||||
|         BOOST_LOG_TRIVIAL(error) << error; | ||||
|         show_error(nullptr, from_u8(error)); | ||||
|     } catch (...) { | ||||
|         const char *error = "Uncaught exception: Unknown error"; | ||||
|         BOOST_LOG_TRIVIAL(error) << error; | ||||
|         show_error(nullptr, from_u8(error)); | ||||
|     } | ||||
| 
 | ||||
|     generic_exception_handle(); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -169,6 +169,7 @@ public: | |||
|     PrintHostJobQueue& printhost_job_queue() { return *m_printhost_job_queue.get(); } | ||||
| 
 | ||||
| private: | ||||
|     bool            on_init_inner(); | ||||
|     void            window_pos_save(wxTopLevelWindow* window, const std::string &name); | ||||
|     void            window_pos_restore(wxTopLevelWindow* window, const std::string &name); | ||||
|     void            window_pos_sanitize(wxTopLevelWindow* window); | ||||
|  |  | |||
|  | @ -62,18 +62,18 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|     // Fill CATEGORY_ICON
 | ||||
|     { | ||||
|         // ptFFF
 | ||||
| 		CATEGORY_ICON[L("Layers and Perimeters")]	= create_scaled_bitmap("layers"); | ||||
| 		CATEGORY_ICON[L("Infill")]					= create_scaled_bitmap("infill"); | ||||
| 		CATEGORY_ICON[L("Support material")]		= create_scaled_bitmap("support"); | ||||
| 		CATEGORY_ICON[L("Speed")]					= create_scaled_bitmap("time"); | ||||
| 		CATEGORY_ICON[L("Extruders")]				= create_scaled_bitmap("funnel"); | ||||
| 		CATEGORY_ICON[L("Extrusion Width")]			= create_scaled_bitmap("funnel"); | ||||
| // 		CATEGORY_ICON[L("Skirt and brim")]			= create_scaled_bitmap("skirt+brim"); 
 | ||||
| // 		CATEGORY_ICON[L("Speed > Acceleration")]	= create_scaled_bitmap("time");
 | ||||
| 		CATEGORY_ICON[L("Advanced")]				= create_scaled_bitmap("wrench"); | ||||
| 		CATEGORY_ICON[L("Layers and Perimeters")]	= create_scaled_bitmap(this, "layers"); | ||||
| 		CATEGORY_ICON[L("Infill")]					= create_scaled_bitmap(this, "infill"); | ||||
| 		CATEGORY_ICON[L("Support material")]		= create_scaled_bitmap(this, "support"); | ||||
| 		CATEGORY_ICON[L("Speed")]					= create_scaled_bitmap(this, "time"); | ||||
| 		CATEGORY_ICON[L("Extruders")]				= create_scaled_bitmap(this, "funnel"); | ||||
| 		CATEGORY_ICON[L("Extrusion Width")]			= create_scaled_bitmap(this, "funnel"); | ||||
| // 		CATEGORY_ICON[L("Skirt and brim")]			= create_scaled_bitmap(this, "skirt+brim"); 
 | ||||
| // 		CATEGORY_ICON[L("Speed > Acceleration")]	= create_scaled_bitmap(this, "time");
 | ||||
| 		CATEGORY_ICON[L("Advanced")]				= create_scaled_bitmap(this, "wrench"); | ||||
| 		// ptSLA
 | ||||
| 		CATEGORY_ICON[L("Supports")]				= create_scaled_bitmap("sla_supports"); | ||||
| 		CATEGORY_ICON[L("Pad")]				        = create_scaled_bitmap("brick.png"); | ||||
| 		CATEGORY_ICON[L("Supports")]				= create_scaled_bitmap(this, "sla_supports"); | ||||
| 		CATEGORY_ICON[L("Pad")]				        = create_scaled_bitmap(this, "brick.png"); | ||||
|     } | ||||
| 
 | ||||
|     // create control
 | ||||
|  | @ -88,7 +88,7 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
|         // before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object
 | ||||
|         // manipulator cache with the following call to selection_changed()
 | ||||
|         wxGetApp().obj_manipul()->emulate_kill_focus(); | ||||
| 
 | ||||
| #else | ||||
|         // To avoid selection update from SetSelection() and UnselectAll() under osx
 | ||||
|         if (m_prevent_list_events) | ||||
|             return; | ||||
|  | @ -141,6 +141,8 @@ ObjectList::ObjectList(wxWindow* parent) : | |||
| #ifdef __WXOSX__ | ||||
|     Bind(wxEVT_KEY_DOWN, &ObjectList::OnChar, this); | ||||
| #endif //__WXOSX__
 | ||||
| 
 | ||||
|     Bind(wxEVT_SIZE, ([this](wxSizeEvent &e) { this->EnsureVisible(this->GetCurrentItem()); e.Skip(); })); | ||||
| } | ||||
| 
 | ||||
| ObjectList::~ObjectList() | ||||
|  | @ -390,10 +392,10 @@ void ObjectList::update_name_in_model(const wxDataViewItem& item) const | |||
| 
 | ||||
| void ObjectList::init_icons() | ||||
| { | ||||
|     m_bmp_modifiermesh     = create_scaled_bitmap("lambda.png"); | ||||
|     m_bmp_solidmesh        = create_scaled_bitmap("object.png"); | ||||
|     m_bmp_support_enforcer = create_scaled_bitmap("support_enforcer_.png"); | ||||
|     m_bmp_support_blocker  = create_scaled_bitmap("support_blocker_.png"); | ||||
|     m_bmp_modifiermesh     = create_scaled_bitmap(this, "lambda.png"); | ||||
|     m_bmp_solidmesh        = create_scaled_bitmap(this, "object.png"); | ||||
|     m_bmp_support_enforcer = create_scaled_bitmap(this, "support_enforcer_.png"); | ||||
|     m_bmp_support_blocker  = create_scaled_bitmap(this, "support_blocker_.png"); | ||||
| 
 | ||||
| 
 | ||||
|     m_bmp_vector.reserve(4); // bitmaps for different types of parts 
 | ||||
|  | @ -404,13 +406,13 @@ void ObjectList::init_icons() | |||
|     m_objects_model->SetVolumeBitmaps(m_bmp_vector); | ||||
| 
 | ||||
|     // init icon for manifold warning
 | ||||
|     m_bmp_manifold_warning  = create_scaled_bitmap("exclamation_mark_.png"); | ||||
|     m_bmp_manifold_warning  = create_scaled_bitmap(this, "exclamation_mark_.png"); | ||||
| 
 | ||||
|     // init bitmap for "Split to sub-objects" context menu
 | ||||
|     m_bmp_split             = create_scaled_bitmap("split_parts"); | ||||
|     m_bmp_split             = create_scaled_bitmap(this, "split_parts"); | ||||
| 
 | ||||
|     // init bitmap for "Add Settings" context menu
 | ||||
|     m_bmp_cog               = create_scaled_bitmap("cog"); | ||||
|     m_bmp_cog               = create_scaled_bitmap(this, "cog"); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1977,7 +1979,7 @@ void ObjectList::update_selections() | |||
|         if (selection.is_single_full_object() &&  | ||||
|             m_objects_model->GetIdByItem(m_objects_model->GetParent(item)) == selection.get_object_idx()) | ||||
|             return;  | ||||
|         if (selection.is_single_volume() || selection.is_modifier()) { | ||||
|         if (selection.is_single_volume() || selection.is_any_modifier()) { | ||||
|             const auto gl_vol = selection.get_volume(*selection.get_volume_idxs().begin()); | ||||
|             if (m_objects_model->GetVolumeIdByItem(m_objects_model->GetParent(item)) == gl_vol->volume_idx()) | ||||
|                 return; | ||||
|  | @ -2012,7 +2014,7 @@ void ObjectList::update_selections() | |||
|             } | ||||
|         } | ||||
|     } | ||||
|     else if (selection.is_single_volume() || selection.is_modifier() || selection.is_multiple_volume())  | ||||
|     else if (selection.is_any_volume() || selection.is_any_modifier()) | ||||
|     { | ||||
|         for (auto idx : selection.get_volume_idxs()) { | ||||
|             const auto gl_vol = selection.get_volume(idx); | ||||
|  | @ -2071,23 +2073,8 @@ void ObjectList::update_selections() | |||
|      | ||||
|     select_items(sels); | ||||
| 
 | ||||
|     /* Because of ScrollLines() and GetItemRect() functions are implemented 
 | ||||
|      * only for GENERIC DataViewCtrl in current version of wxWidgets, | ||||
|      * use this part of code only for MSW  | ||||
|      */ | ||||
| #if defined(wxUSE_GENERICDATAVIEWCTRL) | ||||
|     // Scroll selected Item in the middle of an object list
 | ||||
|     if (GetSelection()) { | ||||
|         const wxRect& sel_rc = GetItemRect(GetSelection()); | ||||
|         const wxRect& main_rc = GetClientRect(); | ||||
|         if (sel_rc.GetBottom() <= main_rc.GetTop()+sel_rc.height || | ||||
|             sel_rc.GetTop() >= main_rc.GetBottom() ) | ||||
|         { | ||||
|             const wxRect& top_rc = GetItemRect(GetTopItem()); | ||||
|             ScrollLines(int((sel_rc.y - top_rc.y) / top_rc.GetHeight()) - 0.5*GetCountPerPage()); | ||||
|         } | ||||
|     } | ||||
| #endif | ||||
|     this->EnsureVisible(this->GetCurrentItem()); | ||||
| } | ||||
| 
 | ||||
| void ObjectList::update_selections_on_canvas() | ||||
|  | @ -2133,6 +2120,7 @@ void ObjectList::update_selections_on_canvas() | |||
|             add_to_selection(item, selection, instance_idx, true); | ||||
| 
 | ||||
|         wxGetApp().plater()->canvas3D()->update_gizmos_on_off_state(); | ||||
|         wxGetApp().plater()->canvas3D()->render(); | ||||
|         return; | ||||
|     } | ||||
|      | ||||
|  |  | |||
|  | @ -92,7 +92,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : | |||
|         else if (option_name == "Size") { | ||||
|             line.near_label_widget = [this](wxWindow* parent) { | ||||
|                 return new wxStaticBitmap(parent, wxID_ANY, wxNullBitmap, wxDefaultPosition, | ||||
|                                           create_scaled_bitmap("one_layer_lock_on.png").GetSize()); | ||||
|                                           create_scaled_bitmap(m_parent, "one_layer_lock_on.png").GetSize()); | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|  |  | |||
|  | @ -77,7 +77,7 @@ void ObjectSettings::update_settings_list() | |||
| 		{ | ||||
| 			auto opt_key = (line.get_options())[0].opt_id;  //we assume that we have one option per line
 | ||||
| 
 | ||||
| 			auto btn = new wxBitmapButton(parent, wxID_ANY, create_scaled_bitmap("colorchange_delete_on.png"), | ||||
| 			auto btn = new wxBitmapButton(parent, wxID_ANY, create_scaled_bitmap(m_parent, "cross"/*"colorchange_delete_on.png"*/), | ||||
| 				wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| #ifdef __WXMSW__ | ||||
|             btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
|  |  | |||
|  | @ -96,11 +96,16 @@ void GLGizmoSlaSupports::on_render(const Selection& selection) const | |||
| 
 | ||||
| void GLGizmoSlaSupports::render_selection_rectangle() const | ||||
| { | ||||
|     if (!m_selection_rectangle_active) | ||||
|     if (m_selection_rectangle_status == srOff) | ||||
|         return; | ||||
| 
 | ||||
|     glsafe(::glLineWidth(1.5f)); | ||||
|     float render_color[3] = {1.f, 0.f, 0.f}; | ||||
|     float render_color[3] = {0.f, 1.f, 0.f}; | ||||
|     if (m_selection_rectangle_status == srDeselect) { | ||||
|         render_color[0] = 1.f; | ||||
|         render_color[1] = 0.3f; | ||||
|         render_color[2] = 0.3f; | ||||
|     } | ||||
|     glsafe(::glColor3fv(render_color)); | ||||
| 
 | ||||
|     glsafe(::glPushAttrib(GL_TRANSFORM_BIT));   // remember current MatrixMode
 | ||||
|  | @ -316,31 +321,35 @@ std::pair<Vec3f, Vec3f> GLGizmoSlaSupports::unproject_on_mesh(const Vec2d& mouse | |||
| // The gizmo has an opportunity to react - if it does, it should return true so that the Canvas3D is
 | ||||
| // aware that the event was reacted to and stops trying to make different sense of it. If the gizmo
 | ||||
| // concludes that the event was not intended for it, it should return false.
 | ||||
| bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down) | ||||
| bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) | ||||
| { | ||||
|     if (m_editing_mode) { | ||||
| 
 | ||||
|         // left down - show the selection rectangle:
 | ||||
|         if (action == SLAGizmoEventType::LeftDown && shift_down) { | ||||
|         // left down with shift - show the selection rectangle:
 | ||||
|         if (action == SLAGizmoEventType::LeftDown && (shift_down || alt_down || control_down)) { | ||||
|             if (m_hover_id == -1) { | ||||
|                 m_selection_rectangle_active = true; | ||||
|                 m_selection_rectangle_start_corner = mouse_position; | ||||
|                 m_selection_rectangle_end_corner = mouse_position; | ||||
|                 m_canvas_width = m_parent.get_canvas_size().get_width(); | ||||
|                 m_canvas_height = m_parent.get_canvas_size().get_height(); | ||||
|                 if (shift_down || alt_down) { | ||||
|                     m_selection_rectangle_status = shift_down ? srSelect : srDeselect; | ||||
|                     m_selection_rectangle_start_corner = mouse_position; | ||||
|                     m_selection_rectangle_end_corner = mouse_position; | ||||
|                     m_canvas_width = m_parent.get_canvas_size().get_width(); | ||||
|                     m_canvas_height = m_parent.get_canvas_size().get_height(); | ||||
|                 } | ||||
|             } | ||||
|             else { | ||||
|                 if (m_editing_mode_cache[m_hover_id].selected) | ||||
|                     unselect_point(m_hover_id); | ||||
|                 else | ||||
|                     select_point(m_hover_id); | ||||
|                 else { | ||||
|                     if (!alt_down) | ||||
|                         select_point(m_hover_id); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         // left down without selection rectangle - place point on the mesh:
 | ||||
|         if (action == SLAGizmoEventType::LeftDown && !m_selection_rectangle_active && !shift_down) { | ||||
|         if (action == SLAGizmoEventType::LeftDown && m_selection_rectangle_status == srOff && !shift_down) { | ||||
|             // If any point is in hover state, this should initiate its move - return control back to GLCanvas:
 | ||||
|             if (m_hover_id != -1) | ||||
|                 return false; | ||||
|  | @ -365,7 +374,7 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous | |||
|         } | ||||
| 
 | ||||
|         // left up with selection rectangle - select points inside the rectangle:
 | ||||
|         if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp) && m_selection_rectangle_active) { | ||||
|         if ((action == SLAGizmoEventType::LeftUp || action == SLAGizmoEventType::ShiftUp || action == SLAGizmoEventType::AltUp) && m_selection_rectangle_status != srOff) { | ||||
|             const Transform3d& instance_matrix = m_model_object->instances[m_active_instance]->get_transformation().get_matrix(); | ||||
|             const Camera& camera = m_parent.get_camera(); | ||||
|             const std::array<int, 4>& viewport = camera.get_viewport(); | ||||
|  | @ -405,11 +414,15 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous | |||
|                         if (hits.size() > 1 || hits.front().t > 0.001f) | ||||
|                             is_obscured = true; | ||||
| 
 | ||||
|                     if (!is_obscured) | ||||
|                         select_point(i); | ||||
|                     if (!is_obscured) { | ||||
|                         if (m_selection_rectangle_status == srDeselect) | ||||
|                             unselect_point(i); | ||||
|                         else | ||||
|                             select_point(i); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             m_selection_rectangle_active = false; | ||||
|             m_selection_rectangle_status = srOff; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|  | @ -427,8 +440,9 @@ bool GLGizmoSlaSupports::gizmo_event(SLAGizmoEventType action, const Vec2d& mous | |||
|                 return true; // point has been placed and the button not released yet
 | ||||
|                              // this prevents GLCanvas from starting scene rotation
 | ||||
| 
 | ||||
|             if (m_selection_rectangle_active)  { | ||||
|             if (m_selection_rectangle_status != srOff)  { | ||||
|                 m_selection_rectangle_end_corner = mouse_position; | ||||
|                 m_selection_rectangle_status = shift_down ? srSelect : srDeselect; | ||||
|                 return true; | ||||
|             } | ||||
| 
 | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ public: | |||
| #endif // ENABLE_SVG_ICONS
 | ||||
|     virtual ~GLGizmoSlaSupports(); | ||||
|     void set_sla_support_data(ModelObject* model_object, const Selection& selection); | ||||
|     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down); | ||||
|     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down); | ||||
|     void delete_selected_points(bool force = false); | ||||
|     std::pair<float, float> get_sla_clipping_plane() const; | ||||
| 
 | ||||
|  | @ -75,7 +75,12 @@ private: | |||
|     mutable std::vector<CacheEntry> m_editing_mode_cache; // a support point and whether it is currently selected
 | ||||
|     float m_clipping_plane_distance = 0.f; | ||||
| 
 | ||||
|     bool m_selection_rectangle_active = false; | ||||
|     enum SelectionRectangleStatus { | ||||
|         srOff = 0, | ||||
|         srSelect = 1, | ||||
|         srDeselect = 2 | ||||
|     }m_selection_rectangle_status = srOff; | ||||
| 
 | ||||
|     Vec2d m_selection_rectangle_start_corner; | ||||
|     Vec2d m_selection_rectangle_end_corner; | ||||
|     bool m_wait_for_up_event = false; | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ enum class SLAGizmoEventType { | |||
|     Delete, | ||||
|     SelectAll, | ||||
|     ShiftUp, | ||||
|     AltUp, | ||||
|     ApplyChanges, | ||||
|     DiscardChanges, | ||||
|     AutomaticGeneration, | ||||
|  |  | |||
|  | @ -455,14 +455,14 @@ void GLGizmosManager::set_sla_support_data(ModelObject* model_object, const Sele | |||
| } | ||||
| 
 | ||||
| // Returns true if the gizmo used the event to do something, false otherwise.
 | ||||
| bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down) | ||||
| bool GLGizmosManager::gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position, bool shift_down, bool alt_down, bool control_down) | ||||
| { | ||||
|     if (!m_enabled) | ||||
|         return false; | ||||
| 
 | ||||
|     GizmosMap::const_iterator it = m_gizmos.find(SlaSupports); | ||||
|     if (it != m_gizmos.end()) | ||||
|         return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->gizmo_event(action, mouse_position, shift_down); | ||||
|         return reinterpret_cast<GLGizmoSlaSupports*>(it->second)->gizmo_event(action, mouse_position, shift_down, alt_down, control_down); | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
|  | @ -546,7 +546,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
| 
 | ||||
|         if (evt.LeftDown()) | ||||
|         { | ||||
|             if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown())) | ||||
|             if ((m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::LeftDown, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) | ||||
|                 // the gizmo got the event and took some action, there is no need to do anything more
 | ||||
|                 processed = true; | ||||
|             else if (!selection.is_empty() && grabber_contains_mouse()) | ||||
|  | @ -573,7 +573,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
|         else if (evt.Dragging() && (canvas.get_move_volume_id() != -1) && (m_current == SlaSupports)) | ||||
|             // don't allow dragging objects with the Sla gizmo on
 | ||||
|             processed = true; | ||||
|         else if (evt.Dragging() && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown())) | ||||
|         else if (evt.Dragging() && (m_current == SlaSupports) && gizmo_event(SLAGizmoEventType::Dragging, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown())) | ||||
|         { | ||||
|             // the gizmo got the event and took some action, no need to do anything more here
 | ||||
|             canvas.set_as_dirty(); | ||||
|  | @ -660,7 +660,7 @@ bool GLGizmosManager::on_mouse(wxMouseEvent& evt, GLCanvas3D& canvas) | |||
|         { | ||||
|             // in case SLA gizmo is selected, we just pass the LeftUp event and stop processing - neither
 | ||||
|             // object moving or selecting is suppressed in that case
 | ||||
|             gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown()); | ||||
|             gizmo_event(SLAGizmoEventType::LeftUp, mouse_pos, evt.ShiftDown(), evt.AltDown(), evt.ControlDown()); | ||||
|             processed = true; | ||||
|         } | ||||
|         else if (evt.LeftUp() && (m_current == Flatten) && ((canvas.get_hover_volume_id() != -1) || grabber_contains_mouse())) | ||||
|  | @ -801,6 +801,10 @@ bool GLGizmosManager::on_key(wxKeyEvent& evt, GLCanvas3D& canvas) | |||
|         if ((m_current == SlaSupports) && (keyCode == WXK_SHIFT) && gizmo_event(SLAGizmoEventType::ShiftUp)) | ||||
|             // shift has been just released - SLA gizmo might want to close rectangular selection.
 | ||||
|             processed = true; | ||||
| 
 | ||||
|         if ((m_current == SlaSupports) && (keyCode == WXK_ALT) && gizmo_event(SLAGizmoEventType::AltUp)) | ||||
|             // alt has been just released - SLA gizmo might want to close rectangular selection.
 | ||||
|             processed = true; | ||||
|     } | ||||
| 
 | ||||
|     if (processed) | ||||
|  |  | |||
|  | @ -145,7 +145,8 @@ public: | |||
|     void set_flattening_data(const ModelObject* model_object); | ||||
| 
 | ||||
|     void set_sla_support_data(ModelObject* model_object, const Selection& selection); | ||||
|     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false); | ||||
|     bool gizmo_event(SLAGizmoEventType action, const Vec2d& mouse_position = Vec2d::Zero(), bool shift_down = false, bool alt_down = false, bool control_down = false); | ||||
| 
 | ||||
| 
 | ||||
|     void render_current_gizmo(const Selection& selection) const; | ||||
|     void render_current_gizmo_for_picking_pass(const Selection& selection) const; | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ KBShortcutsDialog::KBShortcutsDialog() | |||
| 	auto main_sizer = new wxBoxSizer(wxVERTICAL); | ||||
| 
 | ||||
|     // logo
 | ||||
| 	const wxBitmap logo_bmp = create_scaled_bitmap("Slic3r_32px.png", 32); | ||||
| 	const wxBitmap logo_bmp = create_scaled_bitmap(this, "Slic3r_32px.png", 32); | ||||
| 
 | ||||
|     // fonts
 | ||||
|     wxFont head_font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT).Bold(); | ||||
|  | @ -119,7 +119,7 @@ void KBShortcutsDialog::fill_shortcuts() | |||
|     main_shortcuts.push_back(Shortcut("+"               ,L("Add Instance to selected object "))); | ||||
|     main_shortcuts.push_back(Shortcut("-"               ,L("Remove Instance from selected object"))); | ||||
|     main_shortcuts.push_back(Shortcut("?"               ,L("Show keyboard shortcuts list"))); | ||||
|     main_shortcuts.push_back(Shortcut("Shift+LeftMouse", L("Select multiple object/Move multiple object"))); | ||||
|     main_shortcuts.push_back(Shortcut(ctrl+"LeftMouse"  ,L("Select multiple object/Move multiple object"))); | ||||
| 
 | ||||
|     m_full_shortcuts.push_back(std::make_pair( _(L("Main Shortcuts")), std::make_pair(main_shortcuts, 0) )); | ||||
| 
 | ||||
|  |  | |||
|  | @ -61,7 +61,7 @@ DPIFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAU | |||
|     /* Load default preset bitmaps before a tabpanel initialization,
 | ||||
|      * but after filling of an em_unit value  | ||||
|      */ | ||||
|     wxGetApp().preset_bundle->load_default_preset_bitmaps(); | ||||
|     wxGetApp().preset_bundle->load_default_preset_bitmaps(this); | ||||
| 
 | ||||
|     // initialize tabpanel and menubar
 | ||||
|     init_tabpanel(); | ||||
|  | @ -327,9 +327,9 @@ void MainFrame::init_menubar() | |||
|         wxMenuItem* item_open = append_menu_item(fileMenu, wxID_ANY, _(L("&Open Project")) + dots + "\tCtrl+O", _(L("Open a project file")), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->load_project(); }, "brick_add.png"); | ||||
|         wxMenuItem* item_save = append_menu_item(fileMenu, wxID_ANY, _(L("&Save Project")) + "\tCtrl+S", _(L("Save current project file")), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "disk.png"); | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(into_path(m_plater->get_project_filename())); }, "save"); | ||||
|         wxMenuItem* item_save_as = append_menu_item(fileMenu, wxID_ANY, _(L("Save Project &as")) + dots + "\tCtrl+Alt+S", _(L("Save current project file as")), | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "disk.png"); | ||||
|             [this](wxCommandEvent&) { if (m_plater) m_plater->export_3mf(); }, "save"); | ||||
| 
 | ||||
|         fileMenu->AppendSeparator(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -23,15 +23,11 @@ namespace Slic3r { | |||
| namespace GUI { | ||||
| 
 | ||||
| 
 | ||||
| MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id) : | ||||
| 	MsgDialog(parent, title, headline, create_scaled_bitmap("Slic3r_192px.png", 192), button_id) | ||||
| {} | ||||
| 
 | ||||
| MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id) : | ||||
| wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), | ||||
| 	boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)), | ||||
| 	content_sizer(new wxBoxSizer(wxVERTICAL)), | ||||
| 	btn_sizer(new wxBoxSizer(wxHORIZONTAL)) | ||||
| MsgDialog::MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id, wxBitmap bitmap) | ||||
| 	: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) | ||||
| 	, boldfont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)) | ||||
| 	, content_sizer(new wxBoxSizer(wxVERTICAL)) | ||||
| 	, btn_sizer(new wxBoxSizer(wxHORIZONTAL)) | ||||
| { | ||||
| 	boldfont.SetWeight(wxFONTWEIGHT_BOLD); | ||||
| 
 | ||||
|  | @ -54,7 +50,11 @@ wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DI | |||
| 
 | ||||
| 	rightsizer->Add(btn_sizer, 0, wxALIGN_RIGHT); | ||||
| 
 | ||||
| 	auto *logo = new wxStaticBitmap(this, wxID_ANY, std::move(bitmap)); | ||||
| 	if (! bitmap.IsOk()) { | ||||
| 		bitmap = create_scaled_bitmap(this, "Slic3r_192px.png", 192); | ||||
| 	} | ||||
| 
 | ||||
| 	logo = new wxStaticBitmap(this, wxID_ANY, wxNullBitmap); | ||||
| 
 | ||||
| 	topsizer->Add(logo, 0, wxALL, BORDER); | ||||
| 	topsizer->Add(rightsizer, 1, wxALL | wxEXPAND, BORDER); | ||||
|  | @ -69,7 +69,6 @@ MsgDialog::~MsgDialog() {} | |||
| 
 | ||||
| ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) | ||||
| 	: MsgDialog(parent, _(L("Slic3r error")), _(L("Slic3r has encountered an error")), | ||||
|         create_scaled_bitmap("Slic3r_192px_grayscale.png"), | ||||
| 		wxID_NONE) | ||||
| 	, msg(msg) | ||||
| { | ||||
|  | @ -97,6 +96,8 @@ ErrorDialog::ErrorDialog(wxWindow *parent, const wxString &msg) | |||
| 	btn_ok->SetFocus(); | ||||
| 	btn_sizer->Add(btn_ok, 0, wxRIGHT, HORIZ_SPACING); | ||||
| 
 | ||||
| 	logo->SetBitmap(create_scaled_bitmap(this, "Slic3r_192px_grayscale.png", 192)); | ||||
| 
 | ||||
|     SetMaxSize(wxSize(-1, CONTENT_MAX_HEIGHT*wxGetApp().em_unit())); | ||||
| 	Fit(); | ||||
| } | ||||
|  |  | |||
|  | @ -12,6 +12,7 @@ | |||
| 
 | ||||
| class wxBoxSizer; | ||||
| class wxCheckBox; | ||||
| class wxStaticBitmap; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -40,12 +41,12 @@ protected: | |||
| 	}; | ||||
| 
 | ||||
| 	// button_id is an id of a button that can be added by default, use wxID_NONE to disable
 | ||||
| 	MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id = wxID_OK); | ||||
| 	MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxBitmap bitmap, wxWindowID button_id = wxID_OK); | ||||
| 	MsgDialog(wxWindow *parent, const wxString &title, const wxString &headline, wxWindowID button_id = wxID_OK, wxBitmap bitmap = wxNullBitmap); | ||||
| 
 | ||||
| 	wxFont boldfont; | ||||
| 	wxBoxSizer *content_sizer; | ||||
| 	wxBoxSizer *btn_sizer; | ||||
| 	wxStaticBitmap *logo; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -286,7 +286,7 @@ wxBitmapComboBox(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(15 * | |||
| #ifdef __WINDOWS__ | ||||
|     edit_btn->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
| #endif | ||||
|     edit_btn->SetBitmap(create_scaled_bitmap("cog")); | ||||
|     edit_btn->SetBitmap(create_scaled_bitmap(this, "cog")); | ||||
|     edit_btn->SetToolTip(_(L("Click to edit preset"))); | ||||
| 
 | ||||
|     edit_btn->Bind(wxEVT_BUTTON, ([preset_type, this](wxCommandEvent) | ||||
|  | @ -747,6 +747,7 @@ Sidebar::Sidebar(Plater *parent) | |||
|             p->plater->export_gcode(); | ||||
|         else | ||||
|             p->plater->reslice(); | ||||
| 		p->plater->select_view_3D("Preview"); | ||||
|     }); | ||||
|     p->btn_send_gcode->Bind(wxEVT_BUTTON, [this](wxCommandEvent&) { p->plater->send_gcode(); }); | ||||
| } | ||||
|  | @ -2314,20 +2315,14 @@ unsigned int Plater::priv::update_background_process(bool force_validation) | |||
|         this->sidebar->show_sliced_info_sizer(false); | ||||
|         // Reset preview canvases. If the print has been invalidated, the preview canvases will be cleared.
 | ||||
|         // Otherwise they will be just refreshed.
 | ||||
|         switch (this->printer_technology) { | ||||
|         case ptFFF: | ||||
|             if (this->preview != nullptr) | ||||
|                 // If the preview is not visible, the following line just invalidates the preview,
 | ||||
|                 // but the G-code paths are calculated first once the preview is made visible.
 | ||||
|                 this->preview->reload_print(); | ||||
|             // We also need to reload 3D scene because of the wipe tower preview box
 | ||||
|             if (this->config->opt_bool("wipe_tower")) | ||||
|                 return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; | ||||
|             break; | ||||
|         case ptSLA: | ||||
|             return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; | ||||
|             break; | ||||
|         } | ||||
| 		if (this->preview != nullptr) | ||||
| 			// If the preview is not visible, the following line just invalidates the preview,
 | ||||
| 			// but the G-code paths or SLA preview are calculated first once the preview is made visible.
 | ||||
| 			this->preview->reload_print(); | ||||
| 		// In FDM mode, we need to reload the 3D scene because of the wipe tower preview box.
 | ||||
| 		// In SLA mode, we need to reload the 3D scene every time to show the support structures.
 | ||||
| 		if (this->printer_technology == ptSLA || (this->printer_technology == ptFFF && this->config->opt_bool("wipe_tower"))) | ||||
| 			return_state |= UPDATE_BACKGROUND_PROCESS_REFRESH_SCENE; | ||||
|     } | ||||
| 
 | ||||
|     if ((invalidated != Print::APPLY_STATUS_UNCHANGED || force_validation) && ! this->background_process.empty()) { | ||||
|  |  | |||
|  | @ -486,7 +486,7 @@ const std::vector<std::string>& Preset::sla_material_options() | |||
|         s_opts = { | ||||
|             "initial_layer_height", | ||||
|             "exposure_time", "initial_exposure_time", | ||||
|             "material_correction_printing", "material_correction_curing", | ||||
|             "material_correction", | ||||
|             "material_notes", | ||||
|             "default_sla_material_profile", | ||||
|             "compatible_prints", "compatible_prints_condition",  | ||||
|  | @ -506,7 +506,9 @@ const std::vector<std::string>& Preset::sla_printer_options() | |||
|             "display_width", "display_height", "display_pixels_x", "display_pixels_y", | ||||
|             "display_orientation", | ||||
|             "fast_tilt_time", "slow_tilt_time", "area_fill", | ||||
|             "printer_correction", | ||||
|             "relative_correction", | ||||
|             "absolute_correction", | ||||
|             "gamma_correction", | ||||
|             "print_host", "printhost_apikey", "printhost_cafile", | ||||
|             "printer_notes", | ||||
|             "inherits" | ||||
|  | @ -797,16 +799,14 @@ bool PresetCollection::delete_current_preset() | |||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool PresetCollection::load_bitmap_default(const std::string &file_name) | ||||
| void PresetCollection::load_bitmap_default(wxWindow *window, const std::string &file_name) | ||||
| { | ||||
| //     return m_bitmap_main_frame->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
|     return load_scaled_bitmap(&m_bitmap_main_frame, file_name); | ||||
|     *m_bitmap_main_frame = create_scaled_bitmap(window, file_name); | ||||
| } | ||||
| 
 | ||||
| bool PresetCollection::load_bitmap_add(const std::string &file_name) | ||||
| void PresetCollection::load_bitmap_add(wxWindow *window, const std::string &file_name) | ||||
| { | ||||
| // 	return m_bitmap_add->LoadFile(wxString::FromUTF8(Slic3r::var(file_name).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
|     return load_scaled_bitmap(&m_bitmap_add, file_name); | ||||
|     *m_bitmap_add = create_scaled_bitmap(window, file_name); | ||||
| } | ||||
| 
 | ||||
| const Preset* PresetCollection::get_selected_preset_parent() const | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ class wxBitmapComboBox; | |||
| class wxChoice; | ||||
| class wxItemContainer; | ||||
| class wxString; | ||||
| class wxWindow; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
|  | @ -276,10 +277,10 @@ public: | |||
|     bool            delete_current_preset(); | ||||
| 
 | ||||
|     // Load default bitmap to be placed at the wxBitmapComboBox of a MainFrame.
 | ||||
|     bool            load_bitmap_default(const std::string &file_name); | ||||
|     void            load_bitmap_default(wxWindow *window, const std::string &file_name); | ||||
| 
 | ||||
|     // Load "add new printer" bitmap to be placed at the wxBitmapComboBox of a MainFrame.
 | ||||
|     bool            load_bitmap_add(const std::string &file_name); | ||||
|     void            load_bitmap_add(wxWindow *window, const std::string &file_name); | ||||
| 
 | ||||
|     // Compatible & incompatible marks, to be placed at the wxBitmapComboBox items.
 | ||||
|     void            set_bitmap_compatible  (const wxBitmap *bmp) { m_bitmap_compatible   = bmp; } | ||||
|  |  | |||
|  | @ -396,55 +396,36 @@ void PresetBundle::export_selections(AppConfig &config) | |||
|     config.set("presets", "printer",      printers.get_selected_preset_name()); | ||||
| } | ||||
| 
 | ||||
| bool PresetBundle::load_compatible_bitmaps() | ||||
| void PresetBundle::load_compatible_bitmaps(wxWindow *window) | ||||
| { | ||||
|     const std::string path_bitmap_compatible   = "flag-green-icon.png"; | ||||
|     const std::string path_bitmap_incompatible = "flag-red-icon.png"; | ||||
|     const std::string path_bitmap_lock         = "sys_lock.png";//"lock.png";
 | ||||
| 	const std::string path_bitmap_lock_open    = "sys_unlock.png";//"lock_open.png";
 | ||||
| //     bool loaded_compatible   = m_bitmapCompatible  ->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_compatible).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| //     bool loaded_incompatible = m_bitmapIncompatible->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_incompatible).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| //     bool loaded_lock = m_bitmapLock->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_lock).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
| //     bool loaded_lock_open = m_bitmapLockOpen->LoadFile(
 | ||||
| //         wxString::FromUTF8(Slic3r::var(path_bitmap_lock_open).c_str()), wxBITMAP_TYPE_PNG);
 | ||||
|     *m_bitmapCompatible     = create_scaled_bitmap(window, "flag_green"); | ||||
|     *m_bitmapIncompatible   = create_scaled_bitmap(window, "flag_red"); | ||||
|     *m_bitmapLock           = create_scaled_bitmap(window, "lock_closed"); | ||||
|     *m_bitmapLockOpen       = create_scaled_bitmap(window, "sys_unlock.png"); | ||||
| 
 | ||||
|     bool loaded_compatible = load_scaled_bitmap(&m_bitmapCompatible, path_bitmap_compatible); | ||||
|     bool loaded_incompatible = load_scaled_bitmap(&m_bitmapIncompatible,path_bitmap_incompatible); | ||||
|     bool loaded_lock = load_scaled_bitmap(&m_bitmapLock, path_bitmap_lock); | ||||
|     bool loaded_lock_open = load_scaled_bitmap(&m_bitmapLockOpen, path_bitmap_lock_open); | ||||
|     prints       .set_bitmap_compatible(m_bitmapCompatible); | ||||
|     filaments    .set_bitmap_compatible(m_bitmapCompatible); | ||||
|     sla_prints   .set_bitmap_compatible(m_bitmapCompatible); | ||||
|     sla_materials.set_bitmap_compatible(m_bitmapCompatible); | ||||
|     printers .set_bitmap_compatible(m_bitmapCompatible); | ||||
| 
 | ||||
|     if (loaded_compatible) { | ||||
|         prints       .set_bitmap_compatible(m_bitmapCompatible); | ||||
|         filaments    .set_bitmap_compatible(m_bitmapCompatible); | ||||
|         sla_prints   .set_bitmap_compatible(m_bitmapCompatible); | ||||
|         sla_materials.set_bitmap_compatible(m_bitmapCompatible); | ||||
| //        printers .set_bitmap_compatible(m_bitmapCompatible);
 | ||||
|     } | ||||
|     if (loaded_incompatible) { | ||||
|         prints       .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|         filaments    .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|         sla_prints   .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|         sla_materials.set_bitmap_incompatible(m_bitmapIncompatible); | ||||
| //        printers .set_bitmap_incompatible(m_bitmapIncompatible);
 | ||||
|     } | ||||
|     if (loaded_lock) { | ||||
|         prints       .set_bitmap_lock(m_bitmapLock); | ||||
|         filaments    .set_bitmap_lock(m_bitmapLock); | ||||
|         sla_prints   .set_bitmap_lock(m_bitmapLock); | ||||
|         sla_materials.set_bitmap_lock(m_bitmapLock); | ||||
|         printers     .set_bitmap_lock(m_bitmapLock); | ||||
|     } | ||||
|     if (loaded_lock_open) { | ||||
|         prints       .set_bitmap_lock_open(m_bitmapLock); | ||||
|         filaments    .set_bitmap_lock_open(m_bitmapLock); | ||||
|         sla_prints   .set_bitmap_lock_open(m_bitmapLock); | ||||
|         sla_materials.set_bitmap_lock_open(m_bitmapLock); | ||||
|         printers     .set_bitmap_lock_open(m_bitmapLock); | ||||
|     } | ||||
|     return loaded_compatible && loaded_incompatible && loaded_lock && loaded_lock_open; | ||||
|     prints       .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|     filaments    .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|     sla_prints   .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|     sla_materials.set_bitmap_incompatible(m_bitmapIncompatible); | ||||
|     printers .set_bitmap_incompatible(m_bitmapIncompatible); | ||||
| 
 | ||||
|     prints       .set_bitmap_lock(m_bitmapLock); | ||||
|     filaments    .set_bitmap_lock(m_bitmapLock); | ||||
|     sla_prints   .set_bitmap_lock(m_bitmapLock); | ||||
|     sla_materials.set_bitmap_lock(m_bitmapLock); | ||||
|     printers     .set_bitmap_lock(m_bitmapLock); | ||||
| 
 | ||||
|     prints       .set_bitmap_lock_open(m_bitmapLock); | ||||
|     filaments    .set_bitmap_lock_open(m_bitmapLock); | ||||
|     sla_prints   .set_bitmap_lock_open(m_bitmapLock); | ||||
|     sla_materials.set_bitmap_lock_open(m_bitmapLock); | ||||
|     printers     .set_bitmap_lock_open(m_bitmapLock); | ||||
| } | ||||
| 
 | ||||
| DynamicPrintConfig PresetBundle::full_config() const | ||||
|  | @ -1446,7 +1427,7 @@ bool PresetBundle::parse_color(const std::string &scolor, unsigned char *rgb_out | |||
|     return true; | ||||
| } | ||||
| 
 | ||||
| void PresetBundle::load_default_preset_bitmaps() | ||||
| void PresetBundle::load_default_preset_bitmaps(wxWindow *window) | ||||
| { | ||||
|     // Clear bitmap cache, before load new scaled default preset bitmaps 
 | ||||
|     m_bitmapCache->clear(); | ||||
|  | @ -1456,13 +1437,13 @@ void PresetBundle::load_default_preset_bitmaps() | |||
|     this->sla_materials.clear_bitmap_cache(); | ||||
|     this->printers.clear_bitmap_cache(); | ||||
| 
 | ||||
|     this->prints.load_bitmap_default("cog"); | ||||
|     this->sla_prints.load_bitmap_default("cog"); | ||||
|     this->filaments.load_bitmap_default("spool.png"); | ||||
|     this->sla_materials.load_bitmap_default("package_green.png"); | ||||
|     this->printers.load_bitmap_default("printer"); | ||||
|     this->printers.load_bitmap_add("add.png"); | ||||
|     this->load_compatible_bitmaps(); | ||||
|     this->prints.load_bitmap_default(window, "cog"); | ||||
|     this->sla_prints.load_bitmap_default(window, "cog"); | ||||
|     this->filaments.load_bitmap_default(window, "spool.png"); | ||||
|     this->sla_materials.load_bitmap_default(window, "resin"); | ||||
|     this->printers.load_bitmap_default(window, "printer"); | ||||
|     this->printers.load_bitmap_add(window, "add.png"); | ||||
|     this->load_compatible_bitmaps(window); | ||||
| } | ||||
| 
 | ||||
| void PresetBundle::update_platter_filament_ui(unsigned int idx_extruder, GUI::PresetComboBox *ui) | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ | |||
| #include <set> | ||||
| #include <boost/filesystem/path.hpp> | ||||
| 
 | ||||
| class wxWindow; | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| 
 | ||||
| namespace GUI { | ||||
|  | @ -127,7 +129,7 @@ public: | |||
| 
 | ||||
|     static bool                 parse_color(const std::string &scolor, unsigned char *rgb_out); | ||||
| 
 | ||||
|     void                        load_default_preset_bitmaps(); | ||||
|     void                        load_default_preset_bitmaps(wxWindow *window); | ||||
| 
 | ||||
| private: | ||||
|     std::string                 load_system_presets(); | ||||
|  | @ -148,7 +150,7 @@ private: | |||
|     // If it is not an external config, then the config will be stored into the user profile directory.
 | ||||
|     void                        load_config_file_config(const std::string &name_or_path, bool is_external, DynamicPrintConfig &&config); | ||||
|     void                        load_config_file_config_bundle(const std::string &path, const boost::property_tree::ptree &tree); | ||||
|     bool                        load_compatible_bitmaps(); | ||||
|     void                        load_compatible_bitmaps(wxWindow *window); | ||||
| 
 | ||||
|     DynamicPrintConfig          full_fff_config() const; | ||||
|     DynamicPrintConfig          full_sla_config() const; | ||||
|  |  | |||
|  | @ -109,19 +109,20 @@ void Selection::add(unsigned int volume_idx, bool as_single_selection) | |||
|     if (is_wipe_tower() && volume->is_wipe_tower) | ||||
|         return; | ||||
| 
 | ||||
|     bool keep_instance_mode = (m_mode == Instance) && !as_single_selection && (is_single_full_instance() || is_multiple_full_instance()); | ||||
|     bool keep_instance_mode = (m_mode == Instance) && !as_single_selection; | ||||
|     bool already_contained = contains_volume(volume_idx); | ||||
| 
 | ||||
|     // resets the current list if needed
 | ||||
|     bool needs_reset = as_single_selection; | ||||
|     bool needs_reset = as_single_selection && !already_contained; | ||||
|     needs_reset |= volume->is_wipe_tower; | ||||
|     needs_reset |= is_wipe_tower() && !volume->is_wipe_tower; | ||||
|     needs_reset |= !keep_instance_mode && !is_modifier() && volume->is_modifier; | ||||
|     needs_reset |= is_modifier() && !volume->is_modifier; | ||||
|     needs_reset |= as_single_selection && !is_any_modifier() && volume->is_modifier; | ||||
|     needs_reset |= is_any_modifier() && !volume->is_modifier; | ||||
| 
 | ||||
|     if (needs_reset) | ||||
|         clear(); | ||||
| 
 | ||||
|     if (!contains_volume(volume_idx)) | ||||
|     if (!already_contained || needs_reset) | ||||
|     { | ||||
|         if (!keep_instance_mode) | ||||
|             m_mode = volume->is_modifier ? Volume : Instance; | ||||
|  | @ -482,30 +483,6 @@ void Selection::translate(const Vec3d& displacement, bool local) | |||
|     m_bounding_box_dirty = true; | ||||
| } | ||||
| 
 | ||||
| static Eigen::Quaterniond rotation_xyz_diff(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     return | ||||
|         // From the current coordinate system to world.
 | ||||
|         Eigen::AngleAxisd(rot_xyz_to(2), Vec3d::UnitZ()) * Eigen::AngleAxisd(rot_xyz_to(1), Vec3d::UnitY()) * Eigen::AngleAxisd(rot_xyz_to(0), Vec3d::UnitX()) * | ||||
|         // From world to the initial coordinate system.
 | ||||
|         Eigen::AngleAxisd(-rot_xyz_from(0), Vec3d::UnitX()) * Eigen::AngleAxisd(-rot_xyz_from(1), Vec3d::UnitY()) * Eigen::AngleAxisd(-rot_xyz_from(2), Vec3d::UnitZ()); | ||||
| } | ||||
| 
 | ||||
| // This should only be called if it is known, that the two rotations only differ in rotation around the Z axis.
 | ||||
| static double rotation_diff_z(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Vec3d  axis = angle_axis.axis(); | ||||
|     double angle = angle_axis.angle(); | ||||
| #ifndef NDEBUG | ||||
|     if (std::abs(angle) > 1e-8) { | ||||
|         assert(std::abs(axis.x()) < 1e-8); | ||||
|         assert(std::abs(axis.y()) < 1e-8); | ||||
|     } | ||||
| #endif /* NDEBUG */ | ||||
|     return (axis.z() < 0) ? -angle : angle; | ||||
| } | ||||
| 
 | ||||
| // Rotate an object around one of the axes. Only one rotation component is expected to be changing.
 | ||||
| void Selection::rotate(const Vec3d& rotation, TransformationType transformation_type) | ||||
| { | ||||
|  | @ -548,7 +525,7 @@ void Selection::rotate(const Vec3d& rotation, TransformationType transformation_ | |||
|                 assert(is_approx(rotation.z(), 0.0)); | ||||
|                 const GLVolume &first_volume = *(*m_volumes)[first_volume_idx]; | ||||
|                 const Vec3d    &rotation = first_volume.get_instance_rotation(); | ||||
|                 double z_diff = rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[first_volume_idx].get_instance_rotation(), m_cache.volumes_data[i].get_instance_rotation()); | ||||
|                 volume.set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|             } | ||||
|             else { | ||||
|  | @ -1538,7 +1515,7 @@ void Selection::render_sidebar_size_hint(Axis axis, double length) const | |||
| #ifndef NDEBUG | ||||
| static bool is_rotation_xy_synchronized(const Vec3d &rot_xyz_from, const Vec3d &rot_xyz_to) | ||||
| { | ||||
|     Eigen::AngleAxisd angle_axis(rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Eigen::AngleAxisd angle_axis(Geometry::rotation_xyz_diff(rot_xyz_from, rot_xyz_to)); | ||||
|     Vec3d  axis = angle_axis.axis(); | ||||
|     double angle = angle_axis.angle(); | ||||
|     if (std::abs(angle) < 1e-8) | ||||
|  | @ -1618,7 +1595,7 @@ void Selection::synchronize_unselected_instances(SyncRotationType sync_rotation_ | |||
|                 break; | ||||
|             case SYNC_ROTATION_GENERAL: | ||||
|                 // generic rotation -> update instance z with the delta of the rotation.
 | ||||
|                 double z_diff = rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); | ||||
|                 double z_diff = Geometry::rotation_diff_z(m_cache.volumes_data[i].get_instance_rotation(), m_cache.volumes_data[j].get_instance_rotation()); | ||||
|                 v->set_instance_rotation(Vec3d(rotation(0), rotation(1), rotation(2) + z_diff)); | ||||
|                 break; | ||||
|             } | ||||
|  |  | |||
|  | @ -213,7 +213,7 @@ public: | |||
| 
 | ||||
|     bool is_empty() const { return m_type == Empty; } | ||||
|     bool is_wipe_tower() const { return m_type == WipeTower; } | ||||
|     bool is_modifier() const { return (m_type == SingleModifier) || (m_type == MultipleModifier); } | ||||
|     bool is_any_modifier() const { return is_single_modifier() || is_multiple_modifier(); } | ||||
|     bool is_single_modifier() const { return m_type == SingleModifier; } | ||||
|     bool is_multiple_modifier() const { return m_type == MultipleModifier; } | ||||
|     bool is_single_full_instance() const; | ||||
|  | @ -222,6 +222,7 @@ public: | |||
|     bool is_multiple_full_object() const { return m_type == MultipleFullObject; } | ||||
|     bool is_single_volume() const { return m_type == SingleVolume; } | ||||
|     bool is_multiple_volume() const { return m_type == MultipleVolume; } | ||||
|     bool is_any_volume() const { return is_single_volume() || is_multiple_volume(); } | ||||
|     bool is_mixed() const { return m_type == Mixed; } | ||||
|     bool is_from_single_instance() const { return get_instance_idx() != -1; } | ||||
|     bool is_from_single_object() const; | ||||
|  |  | |||
|  | @ -52,7 +52,7 @@ SysInfoDialog::SysInfoDialog() | |||
| 	main_sizer->Add(hsizer, 1, wxEXPAND | wxALL, 10); | ||||
| 
 | ||||
|     // logo
 | ||||
|     auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap("Slic3r_192px.png", 192)); | ||||
|     auto *logo = new wxStaticBitmap(this, wxID_ANY, create_scaled_bitmap(this, "Slic3r_192px.png", 192)); | ||||
| 	hsizer->Add(logo, 0, wxALIGN_CENTER_VERTICAL); | ||||
|      | ||||
|     wxBoxSizer* vsizer = new wxBoxSizer(wxVERTICAL); | ||||
|  |  | |||
|  | @ -116,16 +116,16 @@ void Tab::create_preset_tab() | |||
| 
 | ||||
| 	//buttons
 | ||||
| 	wxBitmap bmpMenu; | ||||
|     bmpMenu = create_scaled_bitmap("disk.png"); | ||||
|     bmpMenu = create_scaled_bitmap(this, "save"); | ||||
| 	m_btn_save_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| 	if (wxMSW) m_btn_save_preset->SetBackgroundColour(color); | ||||
|     bmpMenu = create_scaled_bitmap("delete.png"); | ||||
|     bmpMenu = create_scaled_bitmap(this, "cross"/*"delete.png"*/); | ||||
| 	m_btn_delete_preset = new wxBitmapButton(panel, wxID_ANY, bmpMenu, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| 	if (wxMSW) m_btn_delete_preset->SetBackgroundColour(color); | ||||
| 
 | ||||
| 	m_show_incompatible_presets = false; | ||||
| 	m_bmp_show_incompatible_presets = create_scaled_bitmap("flag-red-icon.png"); | ||||
| 	m_bmp_hide_incompatible_presets = create_scaled_bitmap("flag-green-icon.png"); | ||||
| 	m_bmp_show_incompatible_presets = create_scaled_bitmap(this, "flag_red"); | ||||
| 	m_bmp_hide_incompatible_presets = create_scaled_bitmap(this, "flag_green"); | ||||
| 	m_btn_hide_incompatible_presets = new wxBitmapButton(panel, wxID_ANY, m_bmp_hide_incompatible_presets, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE); | ||||
| 	if (wxMSW) m_btn_hide_incompatible_presets->SetBackgroundColour(color); | ||||
| 
 | ||||
|  | @ -148,13 +148,13 @@ void Tab::create_preset_tab() | |||
| 	// Determine the theme color of OS (dark or light)
 | ||||
|     auto luma = wxGetApp().get_colour_approx_luma(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
| 	// Bitmaps to be shown on the "Revert to system" aka "Lock to system" button next to each input field.
 | ||||
| 	m_bmp_value_lock  	   = create_scaled_bitmap("sys_lock.png"); | ||||
| 	m_bmp_value_unlock     = create_scaled_bitmap(luma >= 128 ? "sys_unlock.png" : "sys_unlock_grey.png"); | ||||
| 	m_bmp_value_lock  	   = create_scaled_bitmap(this, luma >= 128 ? "lock_closed" : "lock_closed_white"); | ||||
| 	m_bmp_value_unlock     = create_scaled_bitmap(this, "lock_open"); | ||||
| 	m_bmp_non_system = &m_bmp_white_bullet; | ||||
| 	// Bitmaps to be shown on the "Undo user changes" button next to each input field.
 | ||||
| 	m_bmp_value_revert    = create_scaled_bitmap(luma >= 128 ? "action_undo.png" : "action_undo_grey.png"); | ||||
| 	m_bmp_white_bullet    = create_scaled_bitmap("bullet_white.png"); | ||||
| 	m_bmp_question        = create_scaled_bitmap("question_mark_01.png"); | ||||
| 	m_bmp_value_revert    = create_scaled_bitmap(this, "undo"); | ||||
| 	m_bmp_white_bullet    = create_scaled_bitmap(this, "bullet_white.png"); | ||||
| 	m_bmp_question        = create_scaled_bitmap(this, "question"); | ||||
| 
 | ||||
| 	fill_icon_descriptions(); | ||||
| 	set_tooltips_text(); | ||||
|  | @ -283,7 +283,7 @@ Slic3r::GUI::PageShp Tab::add_options_page(const wxString& title, const std::str | |||
| 			// Add a new icon to the icon list.
 | ||||
| //             wxIcon img_icon(from_u8(Slic3r::var(icon)), wxBITMAP_TYPE_PNG);
 | ||||
| //             m_icons->Add(img_icon);
 | ||||
|             m_icons->Add(create_scaled_bitmap(icon)); | ||||
|             m_icons->Add(create_scaled_bitmap(this, icon)); | ||||
|             icon_idx = ++m_icon_count; | ||||
| 			m_icon_index[icon] = icon_idx; | ||||
| 		} | ||||
|  | @ -1642,7 +1642,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) | |||
|         auto btn = m_printhost_browse_btn = new wxButton(parent, wxID_ANY, _(L(" Browse ")) + dots,  | ||||
|             wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
| 		btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
|         btn->SetBitmap(create_scaled_bitmap("zoom.png")); | ||||
|         btn->SetBitmap(create_scaled_bitmap(this, "zoom.png")); | ||||
| 		auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 		sizer->Add(btn); | ||||
| 
 | ||||
|  | @ -1661,7 +1661,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) | |||
| 		auto btn = m_print_host_test_btn = new wxButton(parent, wxID_ANY, _(L("Test")),  | ||||
| 			wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
| 		btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
|         btn->SetBitmap(create_scaled_bitmap("wrench.png")); | ||||
|         btn->SetBitmap(create_scaled_bitmap(this, "wrench.png")); | ||||
| 		auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 		sizer->Add(btn); | ||||
| 
 | ||||
|  | @ -1698,7 +1698,7 @@ void TabPrinter::build_printhost(ConfigOptionsGroup *optgroup) | |||
| 		auto printhost_cafile_browse = [this, optgroup] (wxWindow* parent) { | ||||
| 			auto btn = new wxButton(parent, wxID_ANY, _(L(" Browse "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT); | ||||
| 			btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
| 			btn->SetBitmap(create_scaled_bitmap("zoom.png")); | ||||
| 			btn->SetBitmap(create_scaled_bitmap(this, "zoom.png")); | ||||
| 			auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 			sizer->Add(btn); | ||||
| 
 | ||||
|  | @ -1776,7 +1776,7 @@ void TabPrinter::build_fff() | |||
| 		line.widget = [this](wxWindow* parent) { | ||||
| 			auto btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
|             btn->SetFont(wxGetApp().small_font()); | ||||
|             btn->SetBitmap(create_scaled_bitmap("printer")); | ||||
|             btn->SetBitmap(create_scaled_bitmap(this, "printer")); | ||||
| 
 | ||||
| 			auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 			sizer->Add(btn); | ||||
|  | @ -1977,7 +1977,7 @@ void TabPrinter::build_sla() | |||
|     line.widget = [this](wxWindow* parent) { | ||||
|         auto btn = new wxButton(parent, wxID_ANY, _(L(" Set ")) + dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
|         btn->SetFont(wxGetApp().small_font()); | ||||
|         btn->SetBitmap(create_scaled_bitmap("printer")); | ||||
|         btn->SetBitmap(create_scaled_bitmap(this, "printer")); | ||||
| 
 | ||||
|         auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
|         sizer->Add(btn); | ||||
|  | @ -2016,16 +2016,19 @@ void TabPrinter::build_sla() | |||
|     optgroup->append_single_option_line("area_fill"); | ||||
| 
 | ||||
|     optgroup = page->new_optgroup(_(L("Corrections"))); | ||||
|     line = Line{ m_config->def()->get("printer_correction")->full_label, "" }; | ||||
|     std::vector<std::string> axes{ "X", "Y", "Z" }; | ||||
|     line = Line{ m_config->def()->get("relative_correction")->full_label, "" }; | ||||
| //    std::vector<std::string> axes{ "X", "Y", "Z" };
 | ||||
|     std::vector<std::string> axes{ "XY", "Z" }; | ||||
|     int id = 0; | ||||
|     for (auto& axis : axes) { | ||||
|         auto opt = optgroup->get_option("printer_correction", id); | ||||
|         auto opt = optgroup->get_option("relative_correction", id); | ||||
|         opt.opt.label = axis; | ||||
|         line.append_option(opt); | ||||
|         ++id; | ||||
|     } | ||||
|     optgroup->append_line(line); | ||||
|     optgroup->append_single_option_line("absolute_correction"); | ||||
|     optgroup->append_single_option_line("gamma_correction"); | ||||
| 
 | ||||
|     optgroup = page->new_optgroup(_(L("Print Host upload"))); | ||||
|     build_printhost(optgroup.get()); | ||||
|  | @ -2919,7 +2922,7 @@ wxSizer* Tab::compatible_widget_create(wxWindow* parent, PresetDependencies &dep | |||
| 	deps.btn = new wxButton(parent, wxID_ANY, _(L(" Set "))+dots, wxDefaultPosition, wxDefaultSize, wxBU_LEFT | wxBU_EXACTFIT); | ||||
| 	deps.btn->SetFont(Slic3r::GUI::wxGetApp().normal_font()); | ||||
| 
 | ||||
|     deps.btn->SetBitmap(create_scaled_bitmap("printer")); | ||||
|     deps.btn->SetBitmap(create_scaled_bitmap(this, "printer")); | ||||
| 
 | ||||
| 	auto sizer = new wxBoxSizer(wxHORIZONTAL); | ||||
| 	sizer->Add((deps.checkbox), 0, wxALIGN_CENTER_VERTICAL); | ||||
|  | @ -3110,7 +3113,7 @@ ConfigOptionsGroupShp Page::new_optgroup(const wxString& title, int noncommon_la | |||
|             bmp_name = mode == comExpert   ? "mode_expert_.png" : | ||||
|                        mode == comAdvanced ? "mode_middle_.png" : "mode_simple_.png"; | ||||
|         }                                | ||||
|         auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : create_scaled_bitmap(bmp_name)); | ||||
|         auto bmp = new wxStaticBitmap(parent, wxID_ANY, bmp_name.empty() ? wxNullBitmap : create_scaled_bitmap(parent, bmp_name)); | ||||
|         bmp->SetBackgroundStyle(wxBG_STYLE_PAINT); | ||||
|         return bmp; | ||||
|     }; | ||||
|  | @ -3218,7 +3221,7 @@ void TabSLAMaterial::build() | |||
|     m_presets = &m_preset_bundle->sla_materials; | ||||
|     load_initial_data(); | ||||
| 
 | ||||
|     auto page = add_options_page(_(L("Material")), "package_green.png"); | ||||
|     auto page = add_options_page(_(L("Material")), "resin"); | ||||
| 
 | ||||
|     auto optgroup = page->new_optgroup(_(L("Layers"))); | ||||
| //     optgroup->append_single_option_line("layer_height");
 | ||||
|  | @ -3230,7 +3233,7 @@ void TabSLAMaterial::build() | |||
| 
 | ||||
|     optgroup = page->new_optgroup(_(L("Corrections"))); | ||||
|     optgroup->label_width = 19 * m_em_unit;//190;
 | ||||
|     std::vector<std::string> corrections = { "material_correction_printing", "material_correction_curing" }; | ||||
|     std::vector<std::string> corrections = {"material_correction"}; | ||||
|     std::vector<std::string> axes{ "X", "Y", "Z" }; | ||||
|     for (auto& opt_key : corrections) { | ||||
|         auto line = Line{ m_config->def()->get(opt_key)->full_label, "" }; | ||||
|  |  | |||
|  | @ -15,6 +15,7 @@ | |||
| #include "GUI_App.hpp" | ||||
| #include "I18N.hpp" | ||||
| #include "ConfigWizard.hpp" | ||||
| #include "wxExtensions.hpp" | ||||
| 
 | ||||
| namespace Slic3r { | ||||
| namespace GUI { | ||||
|  | @ -108,8 +109,10 @@ MsgUpdateConfig::~MsgUpdateConfig() {} | |||
| // MsgDataIncompatible
 | ||||
| 
 | ||||
| MsgDataIncompatible::MsgDataIncompatible(const std::unordered_map<std::string, wxString> &incompats) : | ||||
| 	MsgDialog(nullptr, _(L("Slic3r incompatibility")), _(L("Slic3r configuration is incompatible")), wxBitmap(from_u8(Slic3r::var("Slic3r_192px_grayscale.png")), wxBITMAP_TYPE_PNG), wxID_NONE) | ||||
| 	MsgDialog(nullptr, _(L("Slic3r incompatibility")), _(L("Slic3r configuration is incompatible")), wxID_NONE) | ||||
| { | ||||
| 	logo->SetBitmap(create_scaled_bitmap(this, "Slic3r_192px_grayscale.png", 192)); | ||||
| 
 | ||||
| 	auto *text = new wxStaticText(this, wxID_ANY, _(L( | ||||
| 		"This version of Slic3r PE is not compatible with currently installed configuration bundles.\n" | ||||
| 		"This probably happened as a result of running an older Slic3r PE after using a newer one.\n\n" | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| #include "wxExtensions.hpp" | ||||
| 
 | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| #include "libslic3r/Utils.hpp" | ||||
| #include "libslic3r/Model.hpp" | ||||
| 
 | ||||
|  | @ -44,7 +46,7 @@ wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const | |||
| wxMenuItem* append_menu_item(wxMenu* menu, int id, const wxString& string, const wxString& description, | ||||
|     std::function<void(wxCommandEvent& event)> cb, const std::string& icon, wxEvtHandler* event_handler) | ||||
| { | ||||
|     const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(icon) : wxNullBitmap; | ||||
|     const wxBitmap& bmp = !icon.empty() ? create_scaled_bitmap(nullptr, icon) : wxNullBitmap;   // FIXME: pass window ptr
 | ||||
|     return append_menu_item(menu, id, string, description, cb, bmp, event_handler); | ||||
| } | ||||
| 
 | ||||
|  | @ -55,7 +57,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin | |||
| 
 | ||||
|     wxMenuItem* item = new wxMenuItem(menu, id, string, description); | ||||
|     if (!icon.empty()) | ||||
|         item->SetBitmap(create_scaled_bitmap(icon)); | ||||
|         item->SetBitmap(create_scaled_bitmap(nullptr, icon));    // FIXME: pass window ptr
 | ||||
| 
 | ||||
|     item->SetSubMenu(sub_menu); | ||||
|     menu->Append(item); | ||||
|  | @ -420,27 +422,36 @@ void PrusaCollapsiblePaneMSW::Collapse(bool collapse) | |||
| 
 | ||||
| 
 | ||||
| // If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
 | ||||
| bool load_scaled_bitmap(wxBitmap** bmp, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /*= false*/) | ||||
| wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/) | ||||
| { | ||||
|     static Slic3r::GUI::BitmapCache cache; | ||||
| 
 | ||||
| #ifdef __APPLE__ | ||||
|     const float scale_factor = win != nullptr ? win->GetContentScaleFactor() : 1.0f; | ||||
| #else | ||||
|     (void)(win); | ||||
|     const float scale_factor = 1.0f; | ||||
| #endif | ||||
| 
 | ||||
|     unsigned int height, width = height = 0; | ||||
|     unsigned int& scale_base = is_horizontal ? width : height; | ||||
| 
 | ||||
|     scale_base = (unsigned int)(Slic3r::GUI::wxGetApp().em_unit() * px_cnt * 0.1f + 0.5f); | ||||
| 
 | ||||
|     std::string bmp_name = bmp_name_in; | ||||
| 	boost::replace_last(bmp_name, ".png", ""); | ||||
|     *bmp = cache.load_svg(bmp_name, width, height); | ||||
|     if (*bmp == nullptr) | ||||
|         *bmp = cache.load_png(bmp_name, width, height); | ||||
|     return *bmp != nullptr; | ||||
| } | ||||
|     boost::replace_last(bmp_name, ".png", ""); | ||||
| 
 | ||||
|     // Try loading an SVG first, then PNG if SVG is not found:
 | ||||
|     wxBitmap *bmp = cache.load_svg(bmp_name, width, height, scale_factor); | ||||
|     if (bmp == nullptr) { | ||||
|         bmp = cache.load_png(bmp_name, width, height); | ||||
|     } | ||||
| 
 | ||||
|     if (bmp == nullptr) { | ||||
|         // Neither SVG nor PNG has been found, raise error
 | ||||
|         throw std::runtime_error("Could not load bitmap: " + bmp_name); | ||||
|     } | ||||
| 
 | ||||
| // If an icon has horizontal orientation (width > height) call this function with is_horizontal = true
 | ||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name_in, const int px_cnt/* = 16*/, const bool is_horizontal /* = false*/) | ||||
| { | ||||
|     wxBitmap *bmp {nullptr}; | ||||
|     load_scaled_bitmap(&bmp, bmp_name_in, px_cnt, is_horizontal); | ||||
|     return *bmp; | ||||
| } | ||||
| 
 | ||||
|  | @ -450,10 +461,10 @@ wxBitmap create_scaled_bitmap(const std::string& bmp_name_in, const int px_cnt/* | |||
| // ----------------------------------------------------------------------------
 | ||||
| 
 | ||||
| void PrusaObjectDataViewModelNode::set_object_action_icon() { | ||||
|     m_action_icon = create_scaled_bitmap("add_object.png"); | ||||
|     m_action_icon = create_scaled_bitmap(nullptr, "add_object.png");    // FIXME: pass window ptr
 | ||||
| } | ||||
| void  PrusaObjectDataViewModelNode::set_part_action_icon() { | ||||
|     m_action_icon = create_scaled_bitmap(m_type == itVolume ? "cog" : "brick_go.png"); | ||||
|     m_action_icon = create_scaled_bitmap(nullptr, m_type == itVolume ? "cog.png" : "brick_go.png");    // FIXME: pass window ptr
 | ||||
| } | ||||
| 
 | ||||
| Slic3r::GUI::BitmapCache *m_bitmap_cache = nullptr; | ||||
|  | @ -1495,20 +1506,20 @@ PrusaDoubleSlider::PrusaDoubleSlider(wxWindow *parent, | |||
|     if (!is_osx) | ||||
|         SetDoubleBuffered(true);// SetDoubleBuffered exists on Win and Linux/GTK, but is missing on OSX
 | ||||
| 
 | ||||
|     m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap("right_half_circle.png") : create_scaled_bitmap("up_half_circle.png",  16, true)); | ||||
|     m_bmp_thumb_lower  = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap("left_half_circle.png" ) : create_scaled_bitmap("down_half_circle.png",16, true)); | ||||
|     m_bmp_thumb_higher = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap(this, "right_half_circle.png") : create_scaled_bitmap(this, "up_half_circle.png",   16, true)); | ||||
|     m_bmp_thumb_lower  = wxBitmap(style == wxSL_HORIZONTAL ? create_scaled_bitmap(this, "left_half_circle.png" ) : create_scaled_bitmap(this, "down_half_circle.png", 16, true)); | ||||
|     m_thumb_size = m_bmp_thumb_lower.GetSize(); | ||||
| 
 | ||||
|     m_bmp_add_tick_on  = create_scaled_bitmap("colorchange_add_on.png"); | ||||
|     m_bmp_add_tick_off = create_scaled_bitmap("colorchange_add_off.png"); | ||||
|     m_bmp_del_tick_on  = create_scaled_bitmap("colorchange_delete_on.png"); | ||||
|     m_bmp_del_tick_off = create_scaled_bitmap("colorchange_delete_off.png"); | ||||
|     m_bmp_add_tick_on  = create_scaled_bitmap(this, "colorchange_add_on.png"); | ||||
|     m_bmp_add_tick_off = create_scaled_bitmap(this, "colorchange_add_off.png"); | ||||
|     m_bmp_del_tick_on  = create_scaled_bitmap(this, "colorchange_delete_on.png"); | ||||
|     m_bmp_del_tick_off = create_scaled_bitmap(this, "colorchange_delete_off.png"); | ||||
|     m_tick_icon_dim = m_bmp_add_tick_on.GetSize().x; | ||||
| 
 | ||||
|     m_bmp_one_layer_lock_on    = create_scaled_bitmap("one_layer_lock_on.png"); | ||||
|     m_bmp_one_layer_lock_off   = create_scaled_bitmap("one_layer_lock_off.png"); | ||||
|     m_bmp_one_layer_unlock_on  = create_scaled_bitmap("one_layer_unlock_on.png"); | ||||
|     m_bmp_one_layer_unlock_off = create_scaled_bitmap("one_layer_unlock_off.png"); | ||||
|     m_bmp_one_layer_lock_on    = create_scaled_bitmap(this, "one_layer_lock_on.png"); | ||||
|     m_bmp_one_layer_lock_off   = create_scaled_bitmap(this, "one_layer_lock_off.png"); | ||||
|     m_bmp_one_layer_unlock_on  = create_scaled_bitmap(this, "one_layer_unlock_on.png"); | ||||
|     m_bmp_one_layer_unlock_off = create_scaled_bitmap(this, "one_layer_unlock_off.png"); | ||||
|     m_lock_icon_dim = m_bmp_one_layer_lock_on.GetSize().x; | ||||
| 
 | ||||
|     m_selection = ssUndef; | ||||
|  | @ -2332,10 +2343,10 @@ PrusaLockButton::PrusaLockButton(   wxWindow *parent, | |||
|                                     const wxSize& size /*= wxDefaultSize*/): | ||||
|                                     wxButton(parent, id, wxEmptyString, pos, size, wxBU_EXACTFIT | wxNO_BORDER) | ||||
| { | ||||
|     m_bmp_lock_on      = create_scaled_bitmap("one_layer_lock_on.png"); | ||||
|     m_bmp_lock_off     = create_scaled_bitmap("one_layer_lock_off.png"); | ||||
|     m_bmp_unlock_on    = create_scaled_bitmap("one_layer_unlock_on.png"); | ||||
|     m_bmp_unlock_off   = create_scaled_bitmap("one_layer_unlock_off.png"); | ||||
|     m_bmp_lock_on      = create_scaled_bitmap(this, "one_layer_lock_on.png"); | ||||
|     m_bmp_lock_off     = create_scaled_bitmap(this, "one_layer_lock_off.png"); | ||||
|     m_bmp_unlock_on    = create_scaled_bitmap(this, "one_layer_unlock_on.png"); | ||||
|     m_bmp_unlock_off   = create_scaled_bitmap(this, "one_layer_unlock_off.png"); | ||||
| 
 | ||||
| 
 | ||||
| #ifdef __WXMSW__ | ||||
|  | @ -2393,7 +2404,7 @@ PrusaModeButton::PrusaModeButton(   wxWindow *parent, | |||
| #ifdef __WXMSW__ | ||||
|     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); | ||||
| #endif // __WXMSW__
 | ||||
|     m_bmp_off = create_scaled_bitmap("mode_off_sq.png"); | ||||
|     m_bmp_off = create_scaled_bitmap(this, "mode_off_sq.png"); | ||||
| 
 | ||||
|     m_tt_focused = wxString::Format(_(L("Switch to the %s mode")), mode); | ||||
|     m_tt_selected = wxString::Format(_(L("Current mode is %s")), mode); | ||||
|  | @ -2447,9 +2458,9 @@ PrusaModeSizer::PrusaModeSizer(wxWindow *parent, int hgap/* = 10*/) : | |||
|     SetFlexibleDirection(wxHORIZONTAL); | ||||
| 
 | ||||
|     std::vector<std::pair<wxString, wxBitmap>> buttons = { | ||||
|         {_(L("Simple")),    create_scaled_bitmap("mode_simple_sq.png")}, | ||||
|         {_(L("Advanced")),  create_scaled_bitmap("mode_middle_sq.png")}, | ||||
|         {_(L("Expert")),    create_scaled_bitmap("mode_expert_sq.png")} | ||||
|         {_(L("Simple")),    create_scaled_bitmap(parent, "mode_simple_sq.png")}, | ||||
|         {_(L("Advanced")),  create_scaled_bitmap(parent, "mode_middle_sq.png")}, | ||||
|         {_(L("Expert")),    create_scaled_bitmap(parent, "mode_expert_sq.png")} | ||||
|     }; | ||||
| 
 | ||||
|     mode_btns.reserve(3); | ||||
|  |  | |||
|  | @ -31,8 +31,7 @@ wxMenuItem* append_submenu(wxMenu* menu, wxMenu* sub_menu, int id, const wxStrin | |||
| wxMenuItem* append_menu_radio_item(wxMenu* menu, int id, const wxString& string, const wxString& description,  | ||||
|     std::function<void(wxCommandEvent& event)> cb, wxEvtHandler* event_handler); | ||||
| 
 | ||||
| bool     load_scaled_bitmap(wxBitmap** bmp, const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false); | ||||
| wxBitmap create_scaled_bitmap(const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false); | ||||
| wxBitmap create_scaled_bitmap(wxWindow *win, const std::string& bmp_name, const int px_cnt=16, const bool is_horizontal = false); | ||||
| 
 | ||||
| class wxCheckListBoxComboPopup : public wxCheckListBox, public wxComboPopup | ||||
| { | ||||
|  |  | |||
 YuSanka
						YuSanka