chiark / gitweb /
Add uppercase STL and HEX to file dialog filters for linux/MacOS
[cura.git] / Cura / 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 #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.
8 import __init__
9
10 import os, sys
11 import types, math
12
13 from newui import profile
14 from fabmetheus_utilities import archive
15
16 def DEFSET(setting):
17         return setting.value
18
19 def storedSetting(name):
20         return lambda setting: profile.getProfileSetting(name)
21 def storedPreference(name):
22         return lambda setting: profile.getPreference(name)
23
24 def ifSettingAboveZero(name):
25         return lambda setting: float(profile.getProfileSetting(name)) > 0
26
27 def ifSettingIs(name, value):
28         return lambda setting: profile.getProfileSetting(name) == value
29
30 def raftLayerCount(setting):
31         if profile.getProfileSetting('enable_raft') == "True":
32                 return '1'
33         return '0'
34
35 def storedPercentSetting(name):
36         return lambda setting: float(profile.getProfileSetting(name)) / 100
37
38 def calculateEdgeWidth(setting):
39         return profile.calculateEdgeWidth()
40
41 def calculateShells(setting):
42         return profile.calculateLineCount() - 1
43
44 def calculateShellsBase(setting):
45         edgeWidth = profile.calculateEdgeWidth()
46         extraWall = float(profile.getProfileSetting('extra_base_wall_thickness'))
47         
48         return profile.calculateLineCount() - 1 + int(extraWall / edgeWidth + 0.0001)
49
50 def calculateSolidLayerCount(setting):
51         return profile.calculateSolidLayerCount()
52
53 def firstLayerSpeedRatio(setting):
54         bottomSpeed = float(profile.getProfileSetting('bottom_layer_speed'))
55         speed = float(profile.getProfileSetting('print_speed'))
56         return bottomSpeed/speed
57
58 def calcSupportDistanceRatio(setting):
59         edgeWidth = calculateEdgeWidth(setting)
60         distance = float(profile.getProfileSetting('support_distance'))
61         return distance / edgeWidth
62
63 def calculateMultiplyDistance(setting):
64         edgeWidth = calculateEdgeWidth(setting)
65         return 10.0 / edgeWidth
66
67 def getProfileInformation():
68         return {
69                 'carve': {
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,
79                         'SVG_Viewer': 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"),
85                 },'scale': {
86                         'Activate_Scale': "False",
87                         'XY_Plane_Scale_ratio': DEFSET,
88                         'Z_Axis_Scale_ratio': DEFSET,
89                         'SVG_Viewer': DEFSET,
90                 },'bottom': {
91                         'Activate_Bottom': DEFSET,
92                         'Additional_Height_over_Layer_Thickness_ratio': DEFSET,
93                         'Altitude_mm': DEFSET,
94                         'SVG_Viewer': DEFSET,
95                 },'preface': {
96                         'Meta': 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,
102                 },'widen': {
103                         'Activate_Widen': DEFSET,
104                         'Widen_Width_over_Edge_Width_ratio': DEFSET,
105                 },'inset': {
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,
113                 },'fill': {
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'),
142                 },'multiply': {
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,
150                 },'speed': {
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"),
170                 },'temperature': {
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"),
181                 },'raft': {
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,
208                 },'skirt': {
209                         'Skirt_line_count': storedSetting("skirt_line_count"),
210                         'Convex': "True",
211                         'Gap_Width_mm': storedSetting("skirt_gap"),
212                         'Layers_To_index': "1",
213                 },'joris': {
214                         'Activate_Joris': storedSetting("joris"),
215                         'Layers_From_index': calculateSolidLayerCount,
216                 },'chamber': {
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,
224                 },'tower': {
225                         'Activate_Tower': "False",
226                         'Extruder_Possible_Collision_Cone_Angle_degrees': DEFSET,
227                         'Maximum_Tower_Height_layers': DEFSET,
228                         'Tower_Start_Layer_integer': DEFSET,
229                 },'jitter': {
230                         'Activate_Jitter': "False",
231                         'Jitter_Over_Perimeter_Width_ratio': DEFSET,
232                 },'clip': {
233                         'Activate_Clip': "False",
234                         'Clip_Over_Perimeter_Width_ratio': DEFSET,
235                         'Maximum_Connection_Distance_Over_Perimeter_Width_ratio': DEFSET,
236                 },'smooth': {
237                         'Activate_Smooth': "False",
238                         'Layers_From_index': DEFSET,
239                         'Maximum_Shortening_over_Width_float': DEFSET,
240                 },'stretch': {
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,
248                 },'skin': {
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,
255                 },'comb': {
256                         'Activate_Comb': "True",
257                         'Running_Jump_Space_mm': DEFSET,
258                 },'cool': {
259                         'Activate_Cool': "True",
260                         'Bridge_Cool_Celcius': DEFSET,
261                         'Cool_Type': 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"),
271                 },'hop': {
272                         'Activate_Hop': "False",
273                         'Hop_Over_Layer_Thickness_ratio': DEFSET,
274                         'Minimum_Hop_Angle_degrees': DEFSET,
275                 },'wipe': {
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,
283                         'Wipe_X_mm': DEFSET,
284                         'Wipe_Y_mm': DEFSET,
285                         'Wipe_Z_mm': DEFSET,
286                         'Wipe_Period_layers': DEFSET,
287                 },'oozebane': {
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,
297                 },'dwindle': {
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,
303                 },'splodge': {
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,
311                 },'home': {
312                         'Activate_Home': "False",
313                         'Name_of_Home_File': DEFSET,
314                 },'lash': {
315                         'Activate_Lash': "False",
316                         'X_Backlash_mm': DEFSET,
317                         'Y_Backlash_mm': DEFSET,
318                 },'fillet': {
319                         'Activate_Fillet': "False",
320                         'Arc_Point': DEFSET,
321                         'Arc_Radius': DEFSET,
322                         'Arc_Segment': DEFSET,
323                         'Bevel': 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,
328                 },'limit': {
329                         'Activate_Limit': "False",
330                         'Maximum_Initial_Feed_Rate_mm/s': DEFSET,
331                 },'unpause': {
332                         'Activate_Unpause': "False",
333                         'Delay_milliseconds': DEFSET,
334                         'Maximum_Speed_ratio': DEFSET,
335                 },'dimension': {
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'),
347                 },'alteration': {
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,
353                 },'export': {
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",
370                 }
371         }
372
373 def safeConfigName(name):
374         return name.replace("=", "").replace(":", "").replace(" ", "_").replace("(", "").replace(")", "")
375
376 def getReadRepository(repository):
377         "Read the configuration for this 'repository'"
378         
379         info = getProfileInformation()
380         if not info.has_key(repository.name):
381                 print "Warning: Plugin: " + repository.name + " missing from Cura info"
382                 return repository
383         info = info[repository.name]
384         
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"
390                         continue
391                 if isinstance(info[name], types.FunctionType):
392                         p.setValueToString(str(info[name](p)))
393                 else:
394                         p.setValueToString(str(info[name]))
395
396         return repository
397
398 def printProgress(layerIndex, procedureName):
399         print ("Progress[" + procedureName + ":" + str(layerIndex+1) + "]")
400         sys.stdout.flush()
401
402 def printProgressByNumber(layerIndex, numberOfLayers, procedureName):
403         print ("Progress[" + procedureName + ":" + str(layerIndex+1) + ":" + str(numberOfLayers) + "]")
404         sys.stdout.flush()
405
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)
409
410 def getAlterationLines(fileName):
411         return archive.getTextLines(getAlterationFile(fileName))
412
413 def getAlterationFile(fileName):
414         return profile.getAlterationFileContents(fileName)
415
416 ####################################
417 ## Configuration settings classes ##
418 ####################################
419
420 class GeneralSetting:
421         "Just a basic setting subclass"
422         def getFromValue( self, name, repository, value ):
423                 #print('GeneralSetting:', name, repository, value )
424                 self.name = name
425                 self.value = value
426                 repository.preferences.append(self)
427                 return self
428
429 class StringSetting(GeneralSetting):
430         "A class to display, read & write a string."
431         def setValueToString(self, value):
432                 self.value = value
433
434 class BooleanSetting( GeneralSetting ):
435         "A class to display, read & write a boolean."
436         def setValueToString(self, value):
437                 self.value = str(value) == "True"
438
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"
442
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 ):
446                 "Initialize."
447                 #print('Radio->getFromRadio:', latentStringVar, name, repository, value )
448                 self.name = name
449                 self.value = value
450                 repository.preferences.append(self)
451                 return self
452
453 class RadioCapitalized( Radio ):
454         "A class to display, read & write a boolean with associated radio button."
455
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 ):
460                 "Initialize."
461                 #print('RadioCapitalizedButton->getFromPath:', latentStringVar, name, path, repository, value )
462                 self.name = name
463                 self.value = value
464                 repository.preferences.append(self)
465                 return self
466                 
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 )
471                 self.name = name
472                 self.value = value
473                 return self
474
475 class HelpPage:
476     "A class to open a help page."
477     def getOpenFromAbsolute( self, hypertextAddress ):
478         return self
479
480 class MenuButtonDisplay:
481         "A class to add a combo box selection."
482         def getFromName( self, name, repository ):
483                 #print('MenuButtonDisplay->getFromName:', name, repository )
484                 self.name = name
485                 self.value = "ERROR"
486                 self.radioList = []
487                 repository.preferences.append(self)
488                 return self
489         
490         def addRadio(self, radio, default):
491                 if default:
492                         self.value = radio.name
493                 self.radioList.append(radio)
494         
495         def setValueToString(self, value):
496                 valueFound = False
497                 for radio in self.radioList:
498                         if radio.name == value:
499                                 valueFound = True;
500                 if valueFound:
501                         self.value = value
502                         for radio in self.radioList:
503                                 radio.value = (radio.name == value)
504
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 ):
508                 "Initialize."
509                 #print('MenuRadio->getFromMenuButtonDisplay:', menuButtonDisplay, name, repository, value )
510                 self.name = name
511                 self.value = value
512                 menuButtonDisplay.addRadio(self, value)
513                 return self
514
515 class LabelDisplay:
516         "A class to add a label."
517         def getFromName( self, name, repository ):
518                 "Initialize."
519                 return self
520
521 class FloatSetting(GeneralSetting):
522         "A class to display, read & write a float."
523         def setValueToString(self, value):
524                 self.value = float(value)
525
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):
529                 "Initialize."
530                 self.name = name
531                 self.value = value
532                 if repository != None:
533                         repository.preferences.append(self)
534                 return self
535
536 class LabelSeparator:
537         "A class to add a label and menu separator."
538         def getFromRepository( self, repository ):
539                 "Initialize."
540                 return self
541
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 ):
545                 "Initialize."
546                 self.name = name
547                 self.value = value
548                 repository.preferences.append(self)
549                 return self
550
551         def setValueToString(self, value):
552                 self.value = int(value)
553
554 ##########################
555 # Helper classes
556 ##########################
557
558 class LayerCount:
559         'A class to handle the layerIndex.'
560         def __init__(self):
561                 'Initialize.'
562                 self.layerIndex = -1
563
564         def __repr__(self):
565                 'Get the string representation of this LayerCount.'
566                 return str(self.layerIndex)
567
568         def printProgressIncrement(self, procedureName):
569                 'Print progress then increment layerIndex.'
570                 self.layerIndex += 1
571                 printProgress(self.layerIndex, procedureName)
572