chiark / gitweb /
Fixed positioning when using multiple extruders. Fixed GCode preview for multiple...
[cura.git] / Cura / cura_sf / fabmetheus_utilities / settings.py
1 """
2 Settings is a collection of utilities to display, read & write the settings and position widgets.
3
4 """
5
6 from __future__ import absolute_import
7 from __future__ import division
8 #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.
9 import __init__
10
11 import os, sys
12 import types, math
13
14 from util import profile
15 from fabmetheus_utilities import archive
16
17 def DEFSET(setting):
18         return setting.value
19
20 def storedSetting(name):
21         return lambda setting: profile.getProfileSetting(name)
22 def storedSettingFloat(name):
23         return lambda setting: profile.getProfileSettingFloat(name)
24 def storedSettingInt(name):
25         return lambda setting: int(profile.getProfileSettingFloat(name))
26 def storedPreference(name):
27         return lambda setting: profile.getPreference(name)
28
29 def ifSettingAboveZero(name):
30         return lambda setting: profile.getProfileSettingFloat(name) > 0
31
32 def ifSettingIs(name, value):
33         return lambda setting: profile.getProfileSetting(name) == value
34
35 def raftLayerCount(setting):
36         if profile.getProfileSetting('enable_raft') == "True":
37                 return '1'
38         return '0'
39
40 def storedPercentSetting(name):
41         return lambda setting: profile.getProfileSettingFloat(name) / 100
42
43 def calculateEdgeWidth(setting):
44         return profile.calculateEdgeWidth()
45
46 def calculateShells(setting):
47         return profile.calculateLineCount() - 1
48
49 def calculateShellsBase(setting):
50         edgeWidth = profile.calculateEdgeWidth()
51         extraWall = profile.getProfileSettingFloat('extra_base_wall_thickness')
52         
53         return profile.calculateLineCount() - 1 + int(extraWall / edgeWidth + 0.0001)
54
55 def calculateSolidLayerCount(setting):
56         return profile.calculateSolidLayerCount()
57
58 def firstLayerSpeedRatio(setting):
59         bottomSpeed = profile.getProfileSettingFloat('bottom_layer_speed')
60         speed = profile.getProfileSettingFloat('print_speed')
61         return bottomSpeed/speed
62
63 def calcSupportDistanceRatio(setting):
64         edgeWidth = calculateEdgeWidth(setting)
65         distance = profile.getProfileSettingFloat('support_distance')
66         return distance / edgeWidth
67
68 def calculateMultiplyDistance(setting):
69         edgeWidth = calculateEdgeWidth(setting)
70         return 10.0 / edgeWidth
71
72 def calcBottomLayerFlowRateRatio(setting):
73         bottomThickness = profile.getProfileSettingFloat('bottom_thickness')
74         layerThickness = profile.getProfileSettingFloat('layer_height')
75         if bottomThickness < layerThickness:
76                 return 1.0
77         return bottomThickness / layerThickness
78
79 def calcExtraBottomThickness(setting):
80         bottomThickness = profile.getProfileSettingFloat('bottom_thickness')
81         layerThickness = profile.getProfileSettingFloat('layer_height')
82         if bottomThickness < layerThickness:
83                 return 0.0
84         return bottomThickness - layerThickness
85
86 def calcLayerSkip(setting):
87         bottomThickness = profile.getProfileSettingFloat('bottom_thickness')
88         layerThickness = profile.getProfileSettingFloat('layer_height')
89         if bottomThickness < layerThickness:
90                 return 0
91         return int(math.ceil((bottomThickness - layerThickness) / layerThickness + 0.0001) - 1)
92
93 def calculateBridgeFlow(setting):
94         return (profile.getProfileSettingFloat('bridge_speed') / 100) * (profile.getProfileSettingFloat('bridge_material_amount') / 100)
95
96 def getProfileInformation():
97         return {
98                 'carve': {
99                         'Add_Layer_Template_to_SVG': DEFSET,
100                         'Edge_Width_mm': calculateEdgeWidth,
101                         'Extra_Decimal_Places_float': DEFSET,
102                         'Import_Coarseness_ratio': DEFSET,
103                         'Layer_Height_mm': storedSettingFloat("layer_height"),
104                         'Layers_From_index': calcLayerSkip,
105                         'Layers_To_index': DEFSET,
106                         'Correct_Mesh': DEFSET,
107                         'Unproven_Mesh': DEFSET,
108                         'SVG_Viewer': DEFSET,
109                         'FlipX': storedSetting("flip_x"),
110                         'FlipY': storedSetting("flip_y"),
111                         'FlipZ': storedSetting("flip_z"),
112                         'SwapXZ': storedSetting("swap_xz"),
113                         'SwapYZ': storedSetting("swap_yz"),
114                         'Scale': storedSettingFloat("model_scale"),
115                         'Rotate': storedSettingFloat("model_rotate_base"),
116                         'CenterX': storedSettingFloat("machine_center_x"),
117                         'CenterY': storedSettingFloat("machine_center_y"),
118                         'AlternativeCenterFile': storedSetting("alternative_center"),
119                 },'scale': {
120                         'Activate_Scale': "False",
121                         'XY_Plane_Scale_ratio': DEFSET,
122                         'Z_Axis_Scale_ratio': DEFSET,
123                         'SVG_Viewer': DEFSET,
124                 },'bottom': {
125                         'Activate_Bottom': DEFSET,
126                         'Additional_Height_over_Layer_Thickness_ratio': DEFSET,
127                         'Altitude_mm': calcExtraBottomThickness,
128                         'SVG_Viewer': DEFSET,
129                 },'preface': {
130                         'Meta': DEFSET,
131                         'Set_Positioning_to_Absolute': "False",
132                         'Set_Units_to_Millimeters': "False",
133                         'Start_at_Home': DEFSET,
134                         'Turn_Extruder_Off_at_Shut_Down': DEFSET,
135                         'Turn_Extruder_Off_at_Start_Up': DEFSET,
136                 },'widen': {
137                         'Activate_Widen': DEFSET,
138                         'Widen_Width_over_Edge_Width_ratio': DEFSET,
139                 },'inset': {
140                         'Add_Custom_Code_for_Temperature_Reading': "False",
141                         'Infill_in_Direction_of_Bridge': "True",
142                         'Infill_Width': storedSettingFloat("nozzle_size"),
143                         'Loop_Order_Choice': DEFSET,
144                         'Overlap_Removal_Width_over_Perimeter_Width_ratio': DEFSET,
145                         'Turn_Extruder_Heater_Off_at_Shut_Down': "False",
146                         'Volume_Fraction_ratio': DEFSET,
147                 },'fill': {
148                         'Activate_Fill': "True",
149                         'Solid_Surface_Top': storedSetting("solid_top"),
150                         'Override_First_Layer_Sequence': storedSetting("force_first_layer_sequence"),
151                         'Diaphragm_Period_layers': DEFSET,
152                         'Diaphragm_Thickness_layers': DEFSET,
153                         'Extra_Shells_on_Alternating_Solid_Layer_layers': calculateShells,
154                         'Extra_Shells_on_Base_layers': calculateShellsBase,
155                         'Extra_Shells_on_Sparse_Layer_layers': calculateShells,
156                         'Grid_Circle_Separation_over_Perimeter_Width_ratio': DEFSET,
157                         'Grid_Extra_Overlap_ratio': DEFSET,
158                         'Grid_Junction_Separation_Band_Height_layers': DEFSET,
159                         'Grid_Junction_Separation_over_Octogon_Radius_At_End_ratio': DEFSET,
160                         'Grid_Junction_Separation_over_Octogon_Radius_At_Middle_ratio': DEFSET,
161                         'Infill_Begin_Rotation_degrees': DEFSET,
162                         'Infill_Begin_Rotation_Repeat_layers': DEFSET,
163                         'Infill_Odd_Layer_Extra_Rotation_degrees': DEFSET,
164                         'Grid_Circular': ifSettingIs('infill_type', 'Grid Circular'),
165                         'Grid_Hexagonal': ifSettingIs('infill_type', 'Grid Hexagonal'),
166                         'Grid_Rectangular': ifSettingIs('infill_type', 'Grid Rectangular'),
167                         'Line': ifSettingIs('infill_type', 'Line'),
168                         'Infill_Perimeter_Overlap_ratio': storedPercentSetting('fill_overlap'),
169                         'Infill_Solidity_ratio': storedPercentSetting('fill_density'),
170                         'Infill_Width': storedSettingFloat("nozzle_size"),
171                         'Sharpest_Angle_degrees': DEFSET,
172                         'Solid_Surface_Thickness_layers': calculateSolidLayerCount,
173                         'Start_From_Choice': DEFSET,
174                         'Surrounding_Angle_degrees': DEFSET,
175                         'Thread_Sequence_Choice': storedSetting('sequence'),
176                 },'multiply': {
177                         'Activate_Multiply': "False",
178                         'Center_X_mm': storedSettingFloat("machine_center_x"),
179                         'Center_Y_mm': storedSettingFloat("machine_center_y"),
180                         'Number_of_Columns_integer': storedSetting('model_multiply_x'),
181                         'Number_of_Rows_integer': storedSetting('model_multiply_y'),
182                         'Reverse_Sequence_every_Odd_Layer': DEFSET,
183                         'Separation_over_Perimeter_Width_ratio': calculateMultiplyDistance,
184                 },'speed': {
185                         'Activate_Speed': "True",
186                         'Add_Flow_Rate': "True",
187                         'Bridge_Feed_Rate_Multiplier_ratio': storedPercentSetting('bridge_speed'),
188                         'Bridge_Flow_Rate_Multiplier_ratio': calculateBridgeFlow,
189                         'Duty_Cyle_at_Beginning_portion': DEFSET,
190                         'Duty_Cyle_at_Ending_portion': DEFSET,
191                         'Feed_Rate_mm/s': storedSettingFloat("print_speed"),
192                         'Flow_Rate_Setting_float': storedSettingFloat("print_speed"),
193                         'Object_First_Layer_Feed_Rate_Infill_Multiplier_ratio': firstLayerSpeedRatio,
194                         'Object_First_Layer_Feed_Rate_Perimeter_Multiplier_ratio': firstLayerSpeedRatio,
195                         'Object_First_Layer_Feed_Rate_Travel_Multiplier_ratio': firstLayerSpeedRatio,
196                         'Object_First_Layer_Flow_Rate_Infill_Multiplier_ratio': firstLayerSpeedRatio,
197                         'Object_First_Layer_Flow_Rate_Perimeter_Multiplier_ratio': firstLayerSpeedRatio,
198                         'Object_First_Layers_Amount_Of_Layers_For_Speed_Change': DEFSET,
199                         'Orbital_Feed_Rate_over_Operating_Feed_Rate_ratio': DEFSET,
200                         'Maximum_Z_Feed_Rate_mm/s': DEFSET,
201                         'Perimeter_Feed_Rate_Multiplier_ratio': DEFSET,
202                         'Perimeter_Flow_Rate_Multiplier_ratio': DEFSET,
203                         'Travel_Feed_Rate_mm/s': storedSettingFloat("travel_speed"),
204                         'Bottom_layer_flow_rate_ratio': calcBottomLayerFlowRateRatio,
205                 },'temperature': {
206                         'Activate_Temperature': DEFSET,#ifSettingAboveZero('print_temperature'),
207                         'Cooling_Rate_Celcius/second': DEFSET,
208                         'Heating_Rate_Celcius/second': DEFSET,
209                         'Base_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
210                         'Interface_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
211                         'Object_First_Layer_Infill_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
212                         'Object_First_Layer_Perimeter_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
213                         'Object_Next_Layers_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
214                         'Support_Layers_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
215                         'Supported_Layers_Temperature_Celcius': DEFSET,#storedSettingFloat("print_temperature"),
216                 },'raft': {
217                         'Activate_Raft': "True",
218                         'Add_Raft,_Elevate_Nozzle,_Orbit': DEFSET,
219                         'Base_Feed_Rate_Multiplier_ratio': DEFSET,
220                         'Base_Flow_Rate_Multiplier_ratio': storedPercentSetting('raft_base_material_amount'),
221                         'Base_Infill_Density_ratio': DEFSET,
222                         'Base_Layer_Thickness_over_Layer_Thickness': DEFSET,
223                         'Base_Layers_integer': raftLayerCount,
224                         'Base_Nozzle_Lift_over_Base_Layer_Thickness_ratio': DEFSET,
225                         'Initial_Circling': DEFSET,
226                         'Infill_Overhang_over_Extrusion_Width_ratio': DEFSET,
227                         'Interface_Feed_Rate_Multiplier_ratio': DEFSET,
228                         'Interface_Flow_Rate_Multiplier_ratio': storedPercentSetting('raft_interface_material_amount'),
229                         'Interface_Infill_Density_ratio': DEFSET,
230                         'Interface_Layer_Thickness_over_Layer_Thickness': DEFSET,
231                         'Interface_Layers_integer': raftLayerCount,
232                         'Interface_Nozzle_Lift_over_Interface_Layer_Thickness_ratio': DEFSET,
233                         'Name_of_Support_End_File': DEFSET,
234                         'Name_of_Support_Start_File': DEFSET,
235                         'Operating_Nozzle_Lift_over_Layer_Thickness_ratio': DEFSET,
236                         'Raft_Additional_Margin_over_Length_%': DEFSET,
237                         'Raft_Margin_mm': storedSettingFloat('raft_margin'),
238                         'Support_Cross_Hatch': 'False',
239                         'Support_Flow_Rate_over_Operating_Flow_Rate_ratio': storedPercentSetting('support_rate'),
240                         'Support_Gap_over_Perimeter_Extrusion_Width_ratio': calcSupportDistanceRatio,
241                         'Support_Material_Choice_': storedSetting('support'),
242                         'Support_Minimum_Angle_degrees': DEFSET,
243                         'Support_Margin_mm': storedSettingFloat('support_margin'),
244                 },'skirt': {
245                         'Skirt_line_count': storedSetting("skirt_line_count"),
246                         'Convex': "True",
247                         'Gap_Width_mm': storedSetting("skirt_gap"),
248                         'Layers_To_index': "1",
249                 },'joris': {
250                         'Activate_Joris': storedSetting("joris"),
251                         'Layers_From_index': calculateSolidLayerCount,
252                 },'chamber': {
253                         'Activate_Chamber': "False",
254                         'Bed_Temperature_Celcius': DEFSET,
255                         'Bed_Temperature_Begin_Change_Height_mm': DEFSET,
256                         'Bed_Temperature_End_Change_Height_mm': DEFSET,
257                         'Bed_Temperature_End_Celcius': DEFSET,
258                         'Chamber_Temperature_Celcius': DEFSET,
259                         'Holding_Force_bar': DEFSET,
260                 },'tower': {
261                         'Activate_Tower': "False",
262                         'Extruder_Possible_Collision_Cone_Angle_degrees': DEFSET,
263                         'Maximum_Tower_Height_layers': DEFSET,
264                         'Tower_Start_Layer_integer': DEFSET,
265                 },'jitter': {
266                         'Activate_Jitter': "False",
267                         'Jitter_Over_Perimeter_Width_ratio': DEFSET,
268                 },'clip': {
269                         'Activate_Clip': "False",
270                         'Clip_Over_Perimeter_Width_ratio': DEFSET,
271                         'Maximum_Connection_Distance_Over_Perimeter_Width_ratio': DEFSET,
272                 },'smooth': {
273                         'Activate_Smooth': "False",
274                         'Layers_From_index': DEFSET,
275                         'Maximum_Shortening_over_Width_float': DEFSET,
276                 },'stretch': {
277                         'Activate_Stretch': "False",
278                         'Cross_Limit_Distance_Over_Perimeter_Width_ratio': DEFSET,
279                         'Loop_Stretch_Over_Perimeter_Width_ratio': DEFSET,
280                         'Path_Stretch_Over_Perimeter_Width_ratio': DEFSET,
281                         'Perimeter_Inside_Stretch_Over_Perimeter_Width_ratio': DEFSET,
282                         'Perimeter_Outside_Stretch_Over_Perimeter_Width_ratio': DEFSET,
283                         'Stretch_From_Distance_Over_Perimeter_Width_ratio': DEFSET,
284                 },'skin': {
285                         'Activate_Skin': storedSetting("enable_skin"),
286                         'Horizontal_Infill_Divisions_integer': "1",
287                         'Horizontal_Perimeter_Divisions_integer': "1",
288                         'Vertical_Divisions_integer': "2",
289                         'Hop_When_Extruding_Infill': "False",
290                         'Layers_From_index': "1",
291                 },'comb': {
292                         'Activate_Comb': "True",
293                         'Running_Jump_Space_mm': DEFSET,
294                 },'cool': {
295                         'Activate_Cool': "True",
296                         'Bridge_Cool_Celcius': DEFSET,
297                         'Cool_Type': DEFSET,
298                         'Maximum_Cool_Celcius': DEFSET,
299                         'Minimum_Layer_Time_seconds': storedSettingFloat("cool_min_layer_time"),
300                         'Minimum_Orbital_Radius_millimeters': DEFSET,
301                         'Name_of_Cool_End_File': DEFSET,
302                         'Name_of_Cool_Start_File': DEFSET,
303                         'Orbital_Outset_millimeters': DEFSET,
304                         'Turn_Fan_On_at_Beginning': storedSetting("fan_enabled"),
305                         'Turn_Fan_Off_at_Ending': storedSetting("fan_enabled"),
306                         'Minimum_feed_rate_mm/s': storedSettingFloat("cool_min_feedrate"),
307                         'Fan_on_at_layer': storedSettingInt('fan_layer'),
308                         'Fan_speed_%': storedSettingInt('fan_speed'),
309                 },'hop': {
310                         'Activate_Hop': "False",
311                         'Hop_Over_Layer_Thickness_ratio': DEFSET,
312                         'Minimum_Hop_Angle_degrees': DEFSET,
313                 },'wipe': {
314                         'Activate_Wipe': "False",
315                         'Arrival_X_mm': DEFSET,
316                         'Arrival_Y_mm': DEFSET,
317                         'Arrival_Z_mm': DEFSET,
318                         'Departure_X_mm': DEFSET,
319                         'Departure_Y_mm': DEFSET,
320                         'Departure_Z_mm': DEFSET,
321                         'Wipe_X_mm': DEFSET,
322                         'Wipe_Y_mm': DEFSET,
323                         'Wipe_Z_mm': DEFSET,
324                         'Wipe_Period_layers': DEFSET,
325                 },'oozebane': {
326                         'Activate_Oozebane': "False",
327                         'After_Startup_Distance_millimeters': DEFSET,
328                         'Early_Shutdown_Distance_millimeters': DEFSET,
329                         'Early_Startup_Distance_Constant_millimeters': DEFSET,
330                         'Early_Startup_Maximum_Distance_millimeters': DEFSET,
331                         'First_Early_Startup_Distance_millimeters': DEFSET,
332                         'Minimum_Distance_for_Early_Startup_millimeters': DEFSET,
333                         'Minimum_Distance_for_Early_Shutdown_millimeters': DEFSET,
334                         'Slowdown_Startup_Steps_positive_integer': DEFSET,
335                 },'dwindle': {
336                         'Activate_Dwindle': "False",
337                         'End_Rate_Multiplier_ratio': DEFSET,
338                         'Pent_Up_Volume_cubic_millimeters': DEFSET,
339                         'Slowdown_Steps_positive_integer': DEFSET,
340                         'Slowdown_Volume_cubic_millimeters': DEFSET,
341                 },'splodge': {
342                         'Activate_Splodge': "False",
343                         'Initial_Lift_over_Extra_Thickness_ratio': DEFSET,
344                         'Initial_Splodge_Feed_Rate_mm/s': DEFSET,
345                         'Operating_Splodge_Feed_Rate_mm/s': DEFSET,
346                         'Operating_Splodge_Quantity_Length_millimeters': DEFSET,
347                         'Initial_Splodge_Quantity_Length_millimeters': DEFSET,
348                         'Operating_Lift_over_Extra_Thickness_ratio': DEFSET,
349                 },'home': {
350                         'Activate_Home': "False",
351                         'Name_of_Home_File': DEFSET,
352                 },'lash': {
353                         'Activate_Lash': "False",
354                         'X_Backlash_mm': DEFSET,
355                         'Y_Backlash_mm': DEFSET,
356                 },'fillet': {
357                         'Activate_Fillet': "False",
358                         'Arc_Point': DEFSET,
359                         'Arc_Radius': DEFSET,
360                         'Arc_Segment': DEFSET,
361                         'Bevel': DEFSET,
362                         'Corner_Feed_Rate_Multiplier_ratio': DEFSET,
363                         'Fillet_Radius_over_Perimeter_Width_ratio': DEFSET,
364                         'Reversal_Slowdown_Distance_over_Perimeter_Width_ratio': DEFSET,
365                         'Use_Intermediate_Feed_Rate_in_Corners': DEFSET,
366                 },'limit': {
367                         'Activate_Limit': "False",
368                         'Maximum_Initial_Feed_Rate_mm/s': DEFSET,
369                 },'unpause': {
370                         'Activate_Unpause': "False",
371                         'Delay_milliseconds': DEFSET,
372                         'Maximum_Speed_ratio': DEFSET,
373                 },'dimension': {
374                         'Activate_Dimension': "True",
375                         'Absolute_Extrusion_Distance': "True",
376                         'Relative_Extrusion_Distance': "False",
377                         'Extruder_Retraction_Speed_mm/s': storedSettingFloat('retraction_speed'),
378                         'Filament_Diameter_mm': storedSettingFloat("filament_diameter"),
379                         'Filament_Packing_Density_ratio': storedSettingFloat("filament_density"),
380                         'Maximum_E_Value_before_Reset_float': DEFSET,
381                         'Minimum_Travel_for_Retraction_millimeters': storedSettingFloat("retraction_min_travel"),
382                         'Retract_Within_Island': DEFSET,
383                         'Retraction_Distance_millimeters': storedSettingFloat('retraction_amount'),
384                         'Restart_Extra_Distance_millimeters': storedSettingFloat('retraction_extra'),
385                 },'alteration': {
386                         'Activate_Alteration': storedSetting('add_start_end_gcode'),
387                         'Name_of_End_File': "end.gcode",
388                         'Name_of_Start_File': "start.gcode",
389                         'Remove_Redundant_Mcode': "True",
390                         'Replace_Variable_with_Setting': DEFSET,
391                 },'export': {
392                         'Activate_Export': "True",
393                         'Add_Descriptive_Extension': DEFSET,
394                         'Add_Export_Suffix': DEFSET,
395                         'Add_Profile_Extension': DEFSET,
396                         'Add_Timestamp_Extension': DEFSET,
397                         'Also_Send_Output_To': DEFSET,
398                         'Analyze_Gcode': DEFSET,
399                         'Comment_Choice': DEFSET,
400                         'Do_Not_Change_Output': DEFSET,
401                         'binary_16_byte': DEFSET,
402                         'gcode_step': DEFSET,
403                         'gcode_time_segment': DEFSET,
404                         'gcode_small': DEFSET,
405                         'File_Extension': storedSetting('gcode_extension'),
406                         'Name_of_Replace_File': DEFSET,
407                         'Save_Penultimate_Gcode': "False",
408                 }
409         }
410
411 def safeConfigName(name):
412         return name.replace("=", "").replace(":", "").replace(" ", "_").replace("(", "").replace(")", "")
413
414 def getReadRepository(repository):
415         "Read the configuration for this 'repository'"
416         
417         info = getProfileInformation()
418         if not info.has_key(repository.name):
419                 print "Warning: Plugin: " + repository.name + " missing from Cura info"
420                 return repository
421         info = info[repository.name]
422         
423         #print('getReadRepository:', repository.name)
424         for p in repository.preferences:
425                 name = safeConfigName(p.name)
426                 if not info.has_key(name):
427                         print "Setting: " + repository.name + ":" + name + " missing from Cura info"
428                         continue
429                 if isinstance(info[name], types.FunctionType):
430                         p.setValueToString(str(info[name](p)))
431                 else:
432                         p.setValueToString(str(info[name]))
433
434         return repository
435
436 def printProgress(layerIndex, procedureName):
437         print ("Progress[" + procedureName + ":" + str(layerIndex+1) + "]")
438         sys.stdout.flush()
439
440 def printProgressByNumber(layerIndex, numberOfLayers, procedureName):
441         print ("Progress[" + procedureName + ":" + str(layerIndex+1) + ":" + str(numberOfLayers) + "]")
442         sys.stdout.flush()
443
444 def getAlterationFileLines(fileName):
445         'Get the alteration file line and the text lines from the fileName in the alterations directories.'
446         return getAlterationLines(fileName)
447
448 def getAlterationLines(fileName):
449         return archive.getTextLines(getAlterationFile(fileName))
450
451 def getAlterationFile(fileName):
452         return profile.getAlterationFileContents(fileName)
453
454 ####################################
455 ## Configuration settings classes ##
456 ####################################
457
458 class GeneralSetting:
459         "Just a basic setting subclass"
460         def getFromValue( self, name, repository, value ):
461                 #print('GeneralSetting:', name, repository, value )
462                 self.name = name
463                 self.value = value
464                 repository.preferences.append(self)
465                 return self
466
467 class StringSetting(GeneralSetting):
468         "A class to display, read & write a string."
469         def setValueToString(self, value):
470                 self.value = value
471
472 class BooleanSetting( GeneralSetting ):
473         "A class to display, read & write a boolean."
474         def setValueToString(self, value):
475                 self.value = str(value) == "True"
476
477 class LatentStringVar:
478         "This is actually used as 'group' object for Radio buttons. (Did I mention the code is a mess?)"
479         "This class doesn't have a name, and isn't really used for anything. It doesn't even know which repository it belongs to"
480
481 class Radio( BooleanSetting ):
482         "A class to display, read & write a boolean with associated radio button."
483         def getFromRadio( self, latentStringVar, name, repository, value ):
484                 "Initialize."
485                 #print('Radio->getFromRadio:', latentStringVar, name, repository, value )
486                 self.name = name
487                 self.value = value
488                 repository.preferences.append(self)
489                 return self
490
491 class RadioCapitalized( Radio ):
492         "A class to display, read & write a boolean with associated radio button."
493
494 class RadioCapitalizedButton( Radio ):
495         "A class to display, read & write a boolean with associated radio button. With an added configuration dialog button"
496         "Only used for the extra export options, which we are not using, so ignore the path for now"
497         def getFromPath( self, latentStringVar, name, path, repository, value ):
498                 "Initialize."
499                 #print('RadioCapitalizedButton->getFromPath:', latentStringVar, name, path, repository, value )
500                 self.name = name
501                 self.value = value
502                 repository.preferences.append(self)
503                 return self
504                 
505 class FileNameInput(StringSetting ):
506         "A class to display, read & write a fileName."
507         def getFromFileName( self, fileTypes, name, repository, value ):
508                 #print('FileNameInput:getFromFileName:', self, fileTypes, name, repository, value )
509                 self.name = name
510                 self.value = value
511                 return self
512
513 class HelpPage:
514     "A class to open a help page."
515     def getOpenFromAbsolute( self, hypertextAddress ):
516         return self
517
518 class MenuButtonDisplay:
519         "A class to add a combo box selection."
520         def getFromName( self, name, repository ):
521                 #print('MenuButtonDisplay->getFromName:', name, repository )
522                 self.name = name
523                 self.value = "ERROR"
524                 self.radioList = []
525                 repository.preferences.append(self)
526                 return self
527         
528         def addRadio(self, radio, default):
529                 if default:
530                         self.value = radio.name
531                 self.radioList.append(radio)
532         
533         def setValueToString(self, value):
534                 valueFound = False
535                 for radio in self.radioList:
536                         if radio.name == value:
537                                 valueFound = True;
538                 if valueFound:
539                         self.value = value
540                         for radio in self.radioList:
541                                 radio.value = (radio.name == value)
542
543 class MenuRadio( BooleanSetting ):
544         "A class to display, read & write a boolean with associated combo box selection."
545         def getFromMenuButtonDisplay( self, menuButtonDisplay, name, repository, value ):
546                 "Initialize."
547                 #print('MenuRadio->getFromMenuButtonDisplay:', menuButtonDisplay, name, repository, value )
548                 self.name = name
549                 self.value = value
550                 menuButtonDisplay.addRadio(self, value)
551                 return self
552
553 class LabelDisplay:
554         "A class to add a label."
555         def getFromName( self, name, repository ):
556                 "Initialize."
557                 return self
558
559 class FloatSetting(GeneralSetting):
560         "A class to display, read & write a float."
561         def setValueToString(self, value):
562                 self.value = float(value)
563
564 class FloatSpin( FloatSetting ):
565         "A class to display, read & write an float in a spin box."
566         def getFromValue(self, from_, name, repository, to, value):
567                 "Initialize."
568                 self.name = name
569                 self.value = value
570                 if repository != None:
571                         repository.preferences.append(self)
572                 return self
573
574 class LabelSeparator:
575         "A class to add a label and menu separator."
576         def getFromRepository( self, repository ):
577                 "Initialize."
578                 return self
579
580 class IntSpin(FloatSpin):
581         "A class to display, read & write an int in a spin box."
582         def getSingleIncrementFromValue( self, from_, name, repository, to, value ):
583                 "Initialize."
584                 self.name = name
585                 self.value = value
586                 repository.preferences.append(self)
587                 return self
588
589         def setValueToString(self, value):
590                 self.value = int(value)
591
592 ##########################
593 # Helper classes
594 ##########################
595
596 class LayerCount:
597         'A class to handle the layerIndex.'
598         def __init__(self):
599                 'Initialize.'
600                 self.layerIndex = -1
601
602         def __repr__(self):
603                 'Get the string representation of this LayerCount.'
604                 return str(self.layerIndex)
605
606         def printProgressIncrement(self, procedureName):
607                 'Print progress then increment layerIndex.'
608                 self.layerIndex += 1
609                 printProgress(self.layerIndex, procedureName)
610