2 Settings is a collection of utilities to display, read & write the settings and position widgets.
6 from __future__ import absolute_import
7 #Init has to be imported first because it has code to workaround the python bug where relative imports don't work if the module is imported as a main module.
13 from gui import profile
14 from fabmetheus_utilities import archive
19 def storedSetting(name):
20 return lambda setting: profile.getProfileSetting(name)
21 def storedPreference(name):
22 return lambda setting: profile.getPreference(name)
24 def ifSettingAboveZero(name):
25 return lambda setting: float(profile.getProfileSetting(name)) > 0
27 def ifSettingIs(name, value):
28 return lambda setting: profile.getProfileSetting(name) == value
30 def raftLayerCount(setting):
31 if profile.getProfileSetting('enable_raft') == "True":
35 def storedPercentSetting(name):
36 return lambda setting: float(profile.getProfileSetting(name)) / 100
38 def calculateEdgeWidth(setting):
39 return profile.calculateEdgeWidth()
41 def calculateShells(setting):
42 return profile.calculateLineCount() - 1
44 def calculateShellsBase(setting):
45 edgeWidth = profile.calculateEdgeWidth()
46 extraWall = float(profile.getProfileSetting('extra_base_wall_thickness'))
48 return profile.calculateLineCount() - 1 + int(extraWall / edgeWidth + 0.0001)
50 def calculateSolidLayerCount(setting):
51 return profile.calculateSolidLayerCount()
53 def firstLayerSpeedRatio(setting):
54 bottomSpeed = float(profile.getProfileSetting('bottom_layer_speed'))
55 speed = float(profile.getProfileSetting('print_speed'))
56 return bottomSpeed/speed
58 def calcSupportDistanceRatio(setting):
59 edgeWidth = calculateEdgeWidth(setting)
60 distance = float(profile.getProfileSetting('support_distance'))
61 return distance / edgeWidth
63 def calculateMultiplyDistance(setting):
64 edgeWidth = calculateEdgeWidth(setting)
65 return 10.0 / edgeWidth
67 def getProfileInformation():
70 'Add_Layer_Template_to_SVG': DEFSET,
71 'Edge_Width_mm': calculateEdgeWidth,
72 'Extra_Decimal_Places_float': DEFSET,
73 'Import_Coarseness_ratio': DEFSET,
74 'Layer_Height_mm': storedSetting("layer_height"),
75 'Layers_From_index': DEFSET,
76 'Layers_To_index': DEFSET,
77 'Correct_Mesh': DEFSET,
78 'Unproven_Mesh': DEFSET,
80 'FlipX': storedSetting("flip_x"),
81 'FlipY': storedSetting("flip_y"),
82 'FlipZ': storedSetting("flip_z"),
83 'Scale': storedSetting("model_scale"),
84 'Rotate': storedSetting("model_rotate_base"),
86 'Activate_Scale': "False",
87 'XY_Plane_Scale_ratio': DEFSET,
88 'Z_Axis_Scale_ratio': DEFSET,
91 'Activate_Bottom': DEFSET,
92 'Additional_Height_over_Layer_Thickness_ratio': DEFSET,
93 'Altitude_mm': DEFSET,
97 'Set_Positioning_to_Absolute': DEFSET,
98 'Set_Units_to_Millimeters': DEFSET,
99 'Start_at_Home': DEFSET,
100 'Turn_Extruder_Off_at_Shut_Down': DEFSET,
101 'Turn_Extruder_Off_at_Start_Up': DEFSET,
103 'Activate_Widen': DEFSET,
104 'Widen_Width_over_Edge_Width_ratio': DEFSET,
106 'Add_Custom_Code_for_Temperature_Reading': DEFSET,
107 'Infill_in_Direction_of_Bridge': "True",
108 'Infill_Width': storedSetting("nozzle_size"),
109 'Loop_Order_Choice': DEFSET,
110 'Overlap_Removal_Width_over_Perimeter_Width_ratio': DEFSET,
111 'Turn_Extruder_Heater_Off_at_Shut_Down': DEFSET,
112 'Volume_Fraction_ratio': DEFSET,
114 'Activate_Fill': "True",
115 'Solid_Surface_Top': storedSetting("solid_top"),
116 'Override_First_Layer_Sequence': storedSetting("force_first_layer_sequence"),
117 'Diaphragm_Period_layers': DEFSET,
118 'Diaphragm_Thickness_layers': DEFSET,
119 'Extra_Shells_on_Alternating_Solid_Layer_layers': calculateShells,
120 'Extra_Shells_on_Base_layers': calculateShellsBase,
121 'Extra_Shells_on_Sparse_Layer_layers': calculateShells,
122 'Grid_Circle_Separation_over_Perimeter_Width_ratio': DEFSET,
123 'Grid_Extra_Overlap_ratio': DEFSET,
124 'Grid_Junction_Separation_Band_Height_layers': DEFSET,
125 'Grid_Junction_Separation_over_Octogon_Radius_At_End_ratio': DEFSET,
126 'Grid_Junction_Separation_over_Octogon_Radius_At_Middle_ratio': DEFSET,
127 'Infill_Begin_Rotation_degrees': DEFSET,
128 'Infill_Begin_Rotation_Repeat_layers': DEFSET,
129 'Infill_Odd_Layer_Extra_Rotation_degrees': DEFSET,
130 'Grid_Circular': ifSettingIs('infill_type', 'Grid Circular'),
131 'Grid_Hexagonal': ifSettingIs('infill_type', 'Grid Hexagonal'),
132 'Grid_Rectangular': ifSettingIs('infill_type', 'Grid Rectangular'),
133 'Line': ifSettingIs('infill_type', 'Line'),
134 'Infill_Perimeter_Overlap_ratio': storedPercentSetting('fill_overlap'),
135 'Infill_Solidity_ratio': storedPercentSetting('fill_density'),
136 'Infill_Width': storedSetting("nozzle_size"),
137 'Sharpest_Angle_degrees': DEFSET,
138 'Solid_Surface_Thickness_layers': calculateSolidLayerCount,
139 'Start_From_Choice': DEFSET,
140 'Surrounding_Angle_degrees': DEFSET,
141 'Thread_Sequence_Choice': storedSetting('sequence'),
143 'Activate_Multiply': "True",
144 'Center_X_mm': storedSetting("machine_center_x"),
145 'Center_Y_mm': storedSetting("machine_center_y"),
146 'Number_of_Columns_integer': storedSetting('model_multiply_x'),
147 'Number_of_Rows_integer': storedSetting('model_multiply_y'),
148 'Reverse_Sequence_every_Odd_Layer': DEFSET,
149 'Separation_over_Perimeter_Width_ratio': calculateMultiplyDistance,
151 'Activate_Speed': "True",
152 'Add_Flow_Rate': "True",
153 'Bridge_Feed_Rate_Multiplier_ratio': storedPercentSetting('bridge_speed'),
154 'Bridge_Flow_Rate_Multiplier_ratio': storedPercentSetting('bridge_material_amount'),
155 'Duty_Cyle_at_Beginning_portion': DEFSET,
156 'Duty_Cyle_at_Ending_portion': DEFSET,
157 'Feed_Rate_mm/s': storedSetting("print_speed"),
158 'Flow_Rate_Setting_float': storedSetting("print_speed"),
159 'Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio': firstLayerSpeedRatio,
160 'Object_First_Layer_Feed_Rate_Perimeter_Multiplier_ratio': firstLayerSpeedRatio,
161 'Object_First_Layer_Feed_Rate_Travel_Multiplier_ratio': firstLayerSpeedRatio,
162 'Object_First_Layer_Flow_Rate_Infill_Multiplier_ratio': firstLayerSpeedRatio,
163 'Object_First_Layer_Flow_Rate_Perimeter_Multiplier_ratio': firstLayerSpeedRatio,
164 'Object_First_Layers_Amount_Of_Layers_For_Speed_Change': DEFSET,
165 'Orbital_Feed_Rate_over_Operating_Feed_Rate_ratio': DEFSET,
166 'Maximum_Z_Feed_Rate_mm/s': DEFSET,
167 'Perimeter_Feed_Rate_Multiplier_ratio': DEFSET,
168 'Perimeter_Flow_Rate_Multiplier_ratio': DEFSET,
169 'Travel_Feed_Rate_mm/s': storedSetting("travel_speed"),
171 'Activate_Temperature': DEFSET,#ifSettingAboveZero('print_temperature'),
172 'Cooling_Rate_Celcius/second': DEFSET,
173 'Heating_Rate_Celcius/second': DEFSET,
174 'Base_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
175 'Interface_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
176 'Object_First_Layer_Infill_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
177 'Object_First_Layer_Perimeter_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
178 'Object_Next_Layers_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
179 'Support_Layers_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
180 'Supported_Layers_Temperature_Celcius': DEFSET,#storedSetting("print_temperature"),
182 'Activate_Raft': "True",
183 'Add_Raft,_Elevate_Nozzle,_Orbit': DEFSET,
184 'Base_Feed_Rate_Multiplier_ratio': DEFSET,
185 'Base_Flow_Rate_Multiplier_ratio': storedPercentSetting('raft_base_material_amount'),
186 'Base_Infill_Density_ratio': DEFSET,
187 'Base_Layer_Thickness_over_Layer_Thickness': DEFSET,
188 'Base_Layers_integer': raftLayerCount,
189 'Base_Nozzle_Lift_over_Base_Layer_Thickness_ratio': DEFSET,
190 'Initial_Circling': DEFSET,
191 'Infill_Overhang_over_Extrusion_Width_ratio': DEFSET,
192 'Interface_Feed_Rate_Multiplier_ratio': DEFSET,
193 'Interface_Flow_Rate_Multiplier_ratio': storedPercentSetting('raft_interface_material_amount'),
194 'Interface_Infill_Density_ratio': DEFSET,
195 'Interface_Layer_Thickness_over_Layer_Thickness': DEFSET,
196 'Interface_Layers_integer': raftLayerCount,
197 'Interface_Nozzle_Lift_over_Interface_Layer_Thickness_ratio': DEFSET,
198 'Name_of_Support_End_File': DEFSET,
199 'Name_of_Support_Start_File': DEFSET,
200 'Operating_Nozzle_Lift_over_Layer_Thickness_ratio': DEFSET,
201 'Raft_Additional_Margin_over_Length_%': DEFSET,
202 'Raft_Margin_mm': storedSetting('raft_margin'),
203 'Support_Cross_Hatch': 'False',
204 'Support_Flow_Rate_over_Operating_Flow_Rate_ratio': storedPercentSetting('support_rate'),
205 'Support_Gap_over_Perimeter_Extrusion_Width_ratio': calcSupportDistanceRatio,
206 'Support_Material_Choice_': storedSetting('support'),
207 'Support_Minimum_Angle_degrees': DEFSET,
209 'Skirt_line_count': storedSetting("skirt_line_count"),
211 'Gap_Width_mm': storedSetting("skirt_gap"),
212 'Layers_To_index': "1",
214 'Activate_Joris': storedSetting("joris"),
215 'Layers_From_index': calculateSolidLayerCount,
217 'Activate_Chamber': "False",
218 'Bed_Temperature_Celcius': DEFSET,
219 'Bed_Temperature_Begin_Change_Height_mm': DEFSET,
220 'Bed_Temperature_End_Change_Height_mm': DEFSET,
221 'Bed_Temperature_End_Celcius': DEFSET,
222 'Chamber_Temperature_Celcius': DEFSET,
223 'Holding_Force_bar': DEFSET,
225 'Activate_Tower': "False",
226 'Extruder_Possible_Collision_Cone_Angle_degrees': DEFSET,
227 'Maximum_Tower_Height_layers': DEFSET,
228 'Tower_Start_Layer_integer': DEFSET,
230 'Activate_Jitter': "False",
231 'Jitter_Over_Perimeter_Width_ratio': DEFSET,
233 'Activate_Clip': "False",
234 'Clip_Over_Perimeter_Width_ratio': DEFSET,
235 'Maximum_Connection_Distance_Over_Perimeter_Width_ratio': DEFSET,
237 'Activate_Smooth': "False",
238 'Layers_From_index': DEFSET,
239 'Maximum_Shortening_over_Width_float': DEFSET,
241 'Activate_Stretch': "False",
242 'Cross_Limit_Distance_Over_Perimeter_Width_ratio': DEFSET,
243 'Loop_Stretch_Over_Perimeter_Width_ratio': DEFSET,
244 'Path_Stretch_Over_Perimeter_Width_ratio': DEFSET,
245 'Perimeter_Inside_Stretch_Over_Perimeter_Width_ratio': DEFSET,
246 'Perimeter_Outside_Stretch_Over_Perimeter_Width_ratio': DEFSET,
247 'Stretch_From_Distance_Over_Perimeter_Width_ratio': DEFSET,
249 'Activate_Skin': "False",
250 'Horizontal_Infill_Divisions_integer': DEFSET,
251 'Horizontal_Perimeter_Divisions_integer': DEFSET,
252 'Vertical_Divisions_integer': DEFSET,
253 'Hop_When_Extruding_Infill': DEFSET,
254 'Layers_From_index': DEFSET,
256 'Activate_Comb': "True",
257 'Running_Jump_Space_mm': DEFSET,
259 'Activate_Cool': "True",
260 'Bridge_Cool_Celcius': DEFSET,
262 'Maximum_Cool_Celcius': DEFSET,
263 'Minimum_Layer_Time_seconds': storedSetting("cool_min_layer_time"),
264 'Minimum_Orbital_Radius_millimeters': DEFSET,
265 'Name_of_Cool_End_File': DEFSET,
266 'Name_of_Cool_Start_File': DEFSET,
267 'Orbital_Outset_millimeters': DEFSET,
268 'Turn_Fan_On_at_Beginning': DEFSET,
269 'Turn_Fan_Off_at_Ending': DEFSET,
270 'Minimum_feed_rate_mm/s': storedSetting("cool_min_feedrate"),
272 'Activate_Hop': "False",
273 'Hop_Over_Layer_Thickness_ratio': DEFSET,
274 'Minimum_Hop_Angle_degrees': DEFSET,
276 'Activate_Wipe': "False",
277 'Arrival_X_mm': DEFSET,
278 'Arrival_Y_mm': DEFSET,
279 'Arrival_Z_mm': DEFSET,
280 'Departure_X_mm': DEFSET,
281 'Departure_Y_mm': DEFSET,
282 'Departure_Z_mm': DEFSET,
286 'Wipe_Period_layers': DEFSET,
288 'Activate_Oozebane': "False",
289 'After_Startup_Distance_millimeters': DEFSET,
290 'Early_Shutdown_Distance_millimeters': DEFSET,
291 'Early_Startup_Distance_Constant_millimeters': DEFSET,
292 'Early_Startup_Maximum_Distance_millimeters': DEFSET,
293 'First_Early_Startup_Distance_millimeters': DEFSET,
294 'Minimum_Distance_for_Early_Startup_millimeters': DEFSET,
295 'Minimum_Distance_for_Early_Shutdown_millimeters': DEFSET,
296 'Slowdown_Startup_Steps_positive_integer': DEFSET,
298 'Activate_Dwindle': "False",
299 'End_Rate_Multiplier_ratio': DEFSET,
300 'Pent_Up_Volume_cubic_millimeters': DEFSET,
301 'Slowdown_Steps_positive_integer': DEFSET,
302 'Slowdown_Volume_cubic_millimeters': DEFSET,
304 'Activate_Splodge': "False",
305 'Initial_Lift_over_Extra_Thickness_ratio': DEFSET,
306 'Initial_Splodge_Feed_Rate_mm/s': DEFSET,
307 'Operating_Splodge_Feed_Rate_mm/s': DEFSET,
308 'Operating_Splodge_Quantity_Length_millimeters': DEFSET,
309 'Initial_Splodge_Quantity_Length_millimeters': DEFSET,
310 'Operating_Lift_over_Extra_Thickness_ratio': DEFSET,
312 'Activate_Home': "False",
313 'Name_of_Home_File': DEFSET,
315 'Activate_Lash': "False",
316 'X_Backlash_mm': DEFSET,
317 'Y_Backlash_mm': DEFSET,
319 'Activate_Fillet': "False",
321 'Arc_Radius': DEFSET,
322 'Arc_Segment': DEFSET,
324 'Corner_Feed_Rate_Multiplier_ratio': DEFSET,
325 'Fillet_Radius_over_Perimeter_Width_ratio': DEFSET,
326 'Reversal_Slowdown_Distance_over_Perimeter_Width_ratio': DEFSET,
327 'Use_Intermediate_Feed_Rate_in_Corners': DEFSET,
329 'Activate_Limit': "False",
330 'Maximum_Initial_Feed_Rate_mm/s': DEFSET,
332 'Activate_Unpause': "False",
333 'Delay_milliseconds': DEFSET,
334 'Maximum_Speed_ratio': DEFSET,
336 'Activate_Dimension': "True",
337 'Absolute_Extrusion_Distance': "True",
338 'Relative_Extrusion_Distance': "False",
339 'Extruder_Retraction_Speed_mm/s': storedSetting('retraction_speed'),
340 'Filament_Diameter_mm': storedSetting("filament_diameter"),
341 'Filament_Packing_Density_ratio': storedSetting("filament_density"),
342 'Maximum_E_Value_before_Reset_float': DEFSET,
343 'Minimum_Travel_for_Retraction_millimeters': storedSetting("retraction_min_travel"),
344 'Retract_Within_Island': DEFSET,
345 'Retraction_Distance_millimeters': storedSetting('retraction_amount'),
346 'Restart_Extra_Distance_millimeters': storedSetting('retraction_extra'),
348 'Activate_Alteration': "True",
349 'Name_of_End_File': "end.gcode",
350 'Name_of_Start_File': "start.gcode",
351 'Remove_Redundant_Mcode': "True",
352 'Replace_Variable_with_Setting': DEFSET,
354 'Activate_Export': "True",
355 'Add_Descriptive_Extension': DEFSET,
356 'Add_Export_Suffix': DEFSET,
357 'Add_Profile_Extension': DEFSET,
358 'Add_Timestamp_Extension': DEFSET,
359 'Also_Send_Output_To': DEFSET,
360 'Analyze_Gcode': DEFSET,
361 'Comment_Choice': DEFSET,
362 'Do_Not_Change_Output': DEFSET,
363 'binary_16_byte': DEFSET,
364 'gcode_step': DEFSET,
365 'gcode_time_segment': DEFSET,
366 'gcode_small': DEFSET,
367 'File_Extension': DEFSET,
368 'Name_of_Replace_File': DEFSET,
369 'Save_Penultimate_Gcode': "False",
373 def safeConfigName(name):
374 return name.replace("=", "").replace(":", "").replace(" ", "_").replace("(", "").replace(")", "")
376 def getReadRepository(repository):
377 "Read the configuration for this 'repository'"
379 info = getProfileInformation()
380 if not info.has_key(repository.name):
381 print "Warning: Plugin: " + repository.name + " missing from Cura info"
383 info = info[repository.name]
385 #print('getReadRepository:', repository.name)
386 for p in repository.preferences:
387 name = safeConfigName(p.name)
388 if not info.has_key(name):
389 print "Setting: " + repository.name + ":" + name + " missing from Cura info"
391 if isinstance(info[name], types.FunctionType):
392 p.setValueToString(str(info[name](p)))
394 p.setValueToString(str(info[name]))
398 def printProgress(layerIndex, procedureName):
399 print ("Progress[" + procedureName + ":" + str(layerIndex+1) + "]")
402 def printProgressByNumber(layerIndex, numberOfLayers, procedureName):
403 print ("Progress[" + procedureName + ":" + str(layerIndex+1) + ":" + str(numberOfLayers) + "]")
406 def getAlterationFileLines(fileName):
407 'Get the alteration file line and the text lines from the fileName in the alterations directories.'
408 return getAlterationLines(fileName)
410 def getAlterationLines(fileName):
411 return archive.getTextLines(getAlterationFile(fileName))
413 def getAlterationFile(fileName):
414 return profile.getAlterationFileContents(fileName)
416 ####################################
417 ## Configuration settings classes ##
418 ####################################
420 class GeneralSetting:
421 "Just a basic setting subclass"
422 def getFromValue( self, name, repository, value ):
423 #print('GeneralSetting:', name, repository, value )
426 repository.preferences.append(self)
429 class StringSetting(GeneralSetting):
430 "A class to display, read & write a string."
431 def setValueToString(self, value):
434 class BooleanSetting( GeneralSetting ):
435 "A class to display, read & write a boolean."
436 def setValueToString(self, value):
437 self.value = str(value) == "True"
439 class LatentStringVar:
440 "This is actually used as 'group' object for Radio buttons. (Did I mention the code is a mess?)"
441 "This class doesn't have a name, and isn't really used for anything. It doesn't even know which repository it belongs to"
443 class Radio( BooleanSetting ):
444 "A class to display, read & write a boolean with associated radio button."
445 def getFromRadio( self, latentStringVar, name, repository, value ):
447 #print('Radio->getFromRadio:', latentStringVar, name, repository, value )
450 repository.preferences.append(self)
453 class RadioCapitalized( Radio ):
454 "A class to display, read & write a boolean with associated radio button."
456 class RadioCapitalizedButton( Radio ):
457 "A class to display, read & write a boolean with associated radio button. With an added configuration dialog button"
458 "Only used for the extra export options, which we are not using, so ignore the path for now"
459 def getFromPath( self, latentStringVar, name, path, repository, value ):
461 #print('RadioCapitalizedButton->getFromPath:', latentStringVar, name, path, repository, value )
464 repository.preferences.append(self)
467 class FileNameInput(StringSetting ):
468 "A class to display, read & write a fileName."
469 def getFromFileName( self, fileTypes, name, repository, value ):
470 #print('FileNameInput:getFromFileName:', self, fileTypes, name, repository, value )
476 "A class to open a help page."
477 def getOpenFromAbsolute( self, hypertextAddress ):
480 class MenuButtonDisplay:
481 "A class to add a combo box selection."
482 def getFromName( self, name, repository ):
483 #print('MenuButtonDisplay->getFromName:', name, repository )
487 repository.preferences.append(self)
490 def addRadio(self, radio, default):
492 self.value = radio.name
493 self.radioList.append(radio)
495 def setValueToString(self, value):
497 for radio in self.radioList:
498 if radio.name == value:
502 for radio in self.radioList:
503 radio.value = (radio.name == value)
505 class MenuRadio( BooleanSetting ):
506 "A class to display, read & write a boolean with associated combo box selection."
507 def getFromMenuButtonDisplay( self, menuButtonDisplay, name, repository, value ):
509 #print('MenuRadio->getFromMenuButtonDisplay:', menuButtonDisplay, name, repository, value )
512 menuButtonDisplay.addRadio(self, value)
516 "A class to add a label."
517 def getFromName( self, name, repository ):
521 class FloatSetting(GeneralSetting):
522 "A class to display, read & write a float."
523 def setValueToString(self, value):
524 self.value = float(value)
526 class FloatSpin( FloatSetting ):
527 "A class to display, read & write an float in a spin box."
528 def getFromValue(self, from_, name, repository, to, value):
532 if repository != None:
533 repository.preferences.append(self)
536 class LabelSeparator:
537 "A class to add a label and menu separator."
538 def getFromRepository( self, repository ):
542 class IntSpin(FloatSpin):
543 "A class to display, read & write an int in a spin box."
544 def getSingleIncrementFromValue( self, from_, name, repository, to, value ):
548 repository.preferences.append(self)
551 def setValueToString(self, value):
552 self.value = int(value)
554 ##########################
556 ##########################
559 'A class to handle the layerIndex.'
565 'Get the string representation of this LayerCount.'
566 return str(self.layerIndex)
568 def printProgressIncrement(self, procedureName):
569 'Print progress then increment layerIndex.'
571 printProgress(self.layerIndex, procedureName)