chiark / gitweb /
Merge pull request #564 from hg42/allow-dropping-profile
authordaid <daid303@gmail.com>
Tue, 24 Sep 2013 13:58:51 +0000 (06:58 -0700)
committerdaid <daid303@gmail.com>
Tue, 24 Sep 2013 13:58:51 +0000 (06:58 -0700)
allow dropping profile (*.ini) onto window

Cura/gui/configWizard.py
Cura/gui/mainWindow.py
Cura/gui/sceneView.py
Cura/gui/simpleMode.py
Cura/gui/tools/youmagineGui.py
Cura/resources/images/Ultimaker2backplate.png [new file with mode: 0644]
Cura/resources/meshes/ultimaker2_platform.stl
Cura/util/profile.py
Cura/util/sliceEngine.py

index e6e4591a1617f0f524d7df12cee7c61e3abbd323..2c2f723b1773bee558f4879e5bbc7c99f82d4305 100644 (file)
@@ -215,15 +215,18 @@ class InfoPage(wx.wizard.WizardPageSimple):
 
 
 class FirstInfoPage(InfoPage):
-       def __init__(self, parent):
-               super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
-               self.AddText(_("Welcome, and thanks for trying Cura!"))
-               self.AddSeperator()
+       def __init__(self, parent, addNew):
+               if addNew:
+                       super(FirstInfoPage, self).__init__(parent, _("Add new machine wizard"))
+               else:
+                       super(FirstInfoPage, self).__init__(parent, _("First time run wizard"))
+                       self.AddText(_("Welcome, and thanks for trying Cura!"))
+                       self.AddSeperator()
                self.AddText(_("This wizard will help you with the following steps:"))
                self.AddText(_("* Configure Cura for your machine"))
-               self.AddText(_("* Upgrade your firmware"))
-               self.AddText(_("* Check if your machine is working safely"))
-               self.AddText(_("* Level your printer bed"))
+               self.AddText(_("* Optionally upgrade your firmware"))
+               self.AddText(_("* Optionally check if your machine is working safely"))
+               self.AddText(_("* Optionally level your printer bed"))
 
                #self.AddText('* Calibrate your machine')
                #self.AddText('* Do your first print')
@@ -327,6 +330,7 @@ class MachineSelectPage(InfoPage):
                        profile.putMachineSetting('gcode_flavor', 'RepRap (Marlin/Sprinter)')
                        profile.putPreference('startMode', 'Normal')
                        profile.putProfileSetting('nozzle_size', '0.5')
+               profile.checkAndUpdateMachineName()
                profile.putProfileSetting('wall_thickness', float(profile.getProfileSetting('nozzle_size')) * 2)
                if self.SubmitUserStats.GetValue():
                        profile.putPreference('submit_slice_information', 'True')
@@ -761,13 +765,13 @@ class Ultimaker2ReadyPage(InfoPage):
                self.AddSeperator()
 
 class configWizard(wx.wizard.Wizard):
-       def __init__(self):
+       def __init__(self, addNew = False):
                super(configWizard, self).__init__(None, -1, "Configuration Wizard")
 
                self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGED, self.OnPageChanged)
                self.Bind(wx.wizard.EVT_WIZARD_PAGE_CHANGING, self.OnPageChanging)
 
-               self.firstInfoPage = FirstInfoPage(self)
+               self.firstInfoPage = FirstInfoPage(self, addNew)
                self.machineSelectPage = MachineSelectPage(self)
                self.ultimakerSelectParts = SelectParts(self)
                self.ultimakerFirmwareUpgradePage = UltimakerFirmwareUpgradePage(self)
index 419f07878cb52239cc3072384e0e1d281cf69541..e1bf8934a1d4c7dc401a8515b943420bde79e450 100644 (file)
@@ -150,6 +150,10 @@ class mainWindow(wx.Frame):
                if self.extruderCount > 1:
                        i = expertMenu.Append(-1, _("Run head offset wizard..."))
                        self.Bind(wx.EVT_MENU, self.OnHeadOffsetWizard, i)
+
+               i = expertMenu.Append(-1, _("Add new machine..."))
+               self.Bind(wx.EVT_MENU, self.OnAddNewMachine, i)
+
                self.menubar.Append(expertMenu, _("Expert"))
 
                helpMenu = wx.Menu()
@@ -408,7 +412,7 @@ class mainWindow(wx.Frame):
                firmwareInstall.InstallFirmware()
 
        def OnCustomFirmware(self, e):
-               if profile.getPreference('machine_type').startswith('ultimaker'):
+               if profile.getMachineSetting('machine_type').startswith('ultimaker'):
                        wx.MessageBox(_("Warning: Installing a custom firmware does not guarantee that you machine will function correctly, and could damage your machine."), _("Firmware update"), wx.OK | wx.ICON_EXCLAMATION)
                dlg=wx.FileDialog(self, _("Open firmware to upload"), os.path.split(profile.getPreference('lastFile'))[0], style=wx.FD_OPEN|wx.FD_FILE_MUST_EXIST)
                dlg.SetWildcard("HEX file (*.hex)|*.hex;*.HEX")
@@ -420,7 +424,19 @@ class mainWindow(wx.Frame):
                        firmwareInstall.InstallFirmware(filename)
 
        def OnFirstRunWizard(self, e):
+               self.Hide()
                configWizard.configWizard()
+               self.Show()
+               self.updateProfileToAllControls()
+
+       def OnAddNewMachine(self, e):
+               self.Hide()
+               n = 0
+               while profile.getMachineSetting('machine_name', n) != '':
+                       n += 1
+               profile.setActiveMachine(n)
+               configWizard.configWizard(True)
+               self.Show()
                self.updateProfileToAllControls()
 
        def OnBedLevelWizard(self, e):
index bd22863e19e356119be9241e5f76821efacc0d70..b65ff526e25562a265c7d8061588a44ac98c56ba 100644 (file)
@@ -1179,7 +1179,7 @@ void main(void)
                                        self._platformMesh[machine] = meshes[0]
                                else:
                                        self._platformMesh[machine] = None
-                               if profile.getMachineSetting('machine_type') == 'ultimaker2':
+                               if machine == 'ultimaker2':
                                        self._platformMesh[machine]._drawOffset = numpy.array([0,-37,145], numpy.float32)
                                else:
                                        self._platformMesh[machine]._drawOffset = numpy.array([0,0,2.5], numpy.float32)
@@ -1187,6 +1187,44 @@ void main(void)
                        self._objectShader.bind()
                        self._renderObject(self._platformMesh[machine], False, False)
                        self._objectShader.unbind()
+
+                       #For the Ultimaker 2 render the texture on the back plate to show the Ultimaker2 text.
+                       if machine == 'ultimaker2':
+                               if not hasattr(self._platformMesh[machine], 'texture'):
+                                       self._platformMesh[machine].texture = opengl.loadGLTexture('Ultimaker2backplate.png')
+                               glBindTexture(GL_TEXTURE_2D, self._platformMesh[machine].texture)
+                               glEnable(GL_TEXTURE_2D)
+                               glPushMatrix()
+                               glColor4f(1,1,1,1)
+
+                               glTranslate(0,150,-5)
+                               h = 50
+                               d = 8
+                               w = 100
+                               glEnable(GL_BLEND)
+                               glBlendFunc(GL_DST_COLOR, GL_ZERO)
+                               glBegin(GL_QUADS)
+                               glTexCoord2f(1, 0)
+                               glVertex3f( w, 0, h)
+                               glTexCoord2f(0, 0)
+                               glVertex3f(-w, 0, h)
+                               glTexCoord2f(0, 1)
+                               glVertex3f(-w, 0, 0)
+                               glTexCoord2f(1, 1)
+                               glVertex3f( w, 0, 0)
+
+                               glTexCoord2f(1, 0)
+                               glVertex3f(-w, d, h)
+                               glTexCoord2f(0, 0)
+                               glVertex3f( w, d, h)
+                               glTexCoord2f(0, 1)
+                               glVertex3f( w, d, 0)
+                               glTexCoord2f(1, 1)
+                               glVertex3f(-w, d, 0)
+                               glEnd()
+                               glDisable(GL_TEXTURE_2D)
+                               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
+                               glPopMatrix()
                else:
                        glColor4f(0,0,0,1)
                        glLineWidth(3)
index 5171dde1a23fc0a4b99f7dc8329eb72e917e9a8e..f34bf3bb928a09662f5e710803b1a559fd9113c1 100644 (file)
@@ -159,7 +159,7 @@ class simpleModePanel(wx.Panel):
                        put('skirt_line_count', '0')
                        put('fan_layer', '1')
                        put('bottom_thickness', '0.0')
-                       put('print_temperature', '260')
+                       put('print_temperature', '245')
                put('plugin_config', '')
 
        def updateProfileToControls(self):
index 126d3a775b74b840a3962e0210c383c9fc5ea5cd..bdf6f9cdeae503a217dae5d479851c29bcf578b3 100644 (file)
@@ -18,7 +18,7 @@ from Cura.util.resources import getPathForImage
 
 from Cura.gui.util import webcam
 
-DESIGN_FILE_EXT = ['.scad', '.blend', '.max', '.stp', '.step', '.igs', '.iges', '.sldasm', '.sldprt', '.skp', '.ipt', '.dwg', '.123d', '.wings']
+DESIGN_FILE_EXT = ['.scad', '.blend', '.max', '.stp', '.step', '.igs', '.iges', '.sldasm', '.sldprt', '.skp', '.iam', '.prt', '.x_t', '.ipt', '.dwg', '.123d', '.wings', '.fcstd', '.top']
 
 def getClipboardText():
        ret = ''
diff --git a/Cura/resources/images/Ultimaker2backplate.png b/Cura/resources/images/Ultimaker2backplate.png
new file mode 100644 (file)
index 0000000..9b663bf
Binary files /dev/null and b/Cura/resources/images/Ultimaker2backplate.png differ
index 9c76445085e79a6f20c11f362178689bb2b6c9cd..5a1bb14001ab6ddb0610165292f2c6fc6e65165b 100644 (file)
Binary files a/Cura/resources/meshes/ultimaker2_platform.stl and b/Cura/resources/meshes/ultimaker2_platform.stl differ
index 5249237f8c1dd67d64ade35d76990a8df57e797d..89740158556b514790ff7bc5765a67c030a982f3 100644 (file)
@@ -13,15 +13,32 @@ from Cura.util import resources
 from Cura.util import version
 from Cura.util import validators
 
+#The settings dictionary contains a key/value reference to all possible settings. With the setting name as key.
 settingsDictionary = {}
+#The settings list is used to keep a full list of all the settings. This is needed to keep the settings in the proper order,
+# as the dictionary will not contain insertion order.
 settingsList = []
+
+#Currently selected machine (by index) Cura support multiple machines in the same preferences and can switch between them.
+# Each machine has it's own index and unique name.
+_selectedMachineIndex = 0
+
 class setting(object):
+       #A setting object contains a configuration setting. These are globally accessible trough the quick access functions
+       # and trough the settingsDictionary function.
+       # Settings can be:
+       # * profile settings (settings that effect the slicing process and the print result)
+       # * preferences (settings that effect how cura works and acts)
+       # * machine settings (settings that relate to the physical configuration of your machine)
+       # * alterations (bad name copied from Skeinforge. These are the start/end code pieces)
+       # Settings have validators that check if the value is valid, but do not prevent invalid values!
+       # Settings have conditions that enable/disable this setting depending on other settings. (Ex: Dual-extrusion)
        def __init__(self, name, default, type, category, subcategory):
                self._name = name
                self._label = name
                self._tooltip = ''
                self._default = unicode(default)
-               self._value = self._default
+               self._values = []
                self._type = type
                self._category = category
                self._subcategory = subcategory
@@ -43,7 +60,7 @@ class setting(object):
                self._tooltip = tooltip
                return self
 
-       def setRange(self, minValue = None, maxValue = None):
+       def setRange(self, minValue=None, maxValue=None):
                if len(self._validators) < 1:
                        return
                self._validators[0].minValue = minValue
@@ -80,14 +97,28 @@ class setting(object):
        def getType(self):
                return self._type
 
-       def getValue(self):
-               return self._value
+       def getValue(self, index = None):
+               if index is None:
+                       index = self.getValueIndex()
+               if index >= len(self._values):
+                       return self._default
+               return self._values[index]
 
        def getDefault(self):
                return self._default
 
-       def setValue(self, value):
-               self._value = unicode(value)
+       def setValue(self, value, index = None):
+               if index is None:
+                       index = self.getValueIndex()
+               while index >= len(self._values):
+                       self._values.append(self._default)
+               self._values[index] = unicode(value)
+
+       def getValueIndex(self):
+               if self.isMachineSetting():
+                       global _selectedMachineIndex
+                       return _selectedMachineIndex
+               return 0
 
        def validate(self):
                result = validators.SUCCESS
@@ -307,6 +338,7 @@ setting('check_for_updates', 'True', bool, 'preference', 'hidden').setLabel('Che
 setting('submit_slice_information', 'False', bool, 'preference', 'hidden').setLabel('Send usage statistics', 'Submit anonymous usage information to improve next versions of Cura')
 setting('youmagine_token', '', str, 'preference', 'hidden')
 setting('filament_physical_density', '1240', float, 'preference', 'hidden').setRange(500.0, 3000.0).setLabel('Density (kg/m3)', 'Weight of the filament per m3. Around 1240 for PLA. And around 1040 for ABS. This value is used to estimate the weight if the filament used for the print.')
+setting('active_machine', '0', int, 'preference', 'hidden')
 
 setting('model_colour', '#FFC924', str, 'preference', 'hidden').setLabel('Model colour')
 setting('model_colour2', '#CB3030', str, 'preference', 'hidden').setLabel('Model colour (2)')
@@ -320,10 +352,11 @@ setting('window_width', '-1', float, 'preference', 'hidden')
 setting('window_height', '-1', float, 'preference', 'hidden')
 setting('window_normal_sash', '320', float, 'preference', 'hidden')
 
+setting('machine_name', '', str, 'machine', 'hidden')
+setting('machine_type', 'unknown', str, 'machine', 'hidden') #Ultimaker, Ultimaker2, RepRap
 setting('machine_width', '205', float, 'machine', 'hidden').setLabel('Maximum width (mm)', 'Size of the machine in mm')
 setting('machine_depth', '205', float, 'machine', 'hidden').setLabel('Maximum depth (mm)', 'Size of the machine in mm')
 setting('machine_height', '200', float, 'machine', 'hidden').setLabel('Maximum height (mm)', 'Size of the machine in mm')
-setting('machine_type', 'unknown', str, 'machine', 'hidden')
 setting('machine_center_is_zero', 'False', bool, 'machine', 'hidden')
 setting('ultimaker_extruder_upgrade', 'False', bool, 'machine', 'hidden')
 setting('has_heated_bed', 'False', bool, 'machine', 'hidden').setLabel('Heated bed', 'If you have an heated bed, this enabled heated bed settings (requires restart)')
@@ -589,32 +622,46 @@ def getPreferenceColour(name):
        return [float(int(colorString[1:3], 16)) / 255, float(int(colorString[3:5], 16)) / 255, float(int(colorString[5:7], 16)) / 255, 1.0]
 
 def loadPreferences(filename):
+       global settingsList
        #Read a configuration file as global config
        profileParser = ConfigParser.ConfigParser()
        try:
                profileParser.read(filename)
        except ConfigParser.ParsingError:
                return
-       global settingsList
+
        for set in settingsList:
                if set.isPreference():
                        if profileParser.has_option('preference', set.getName()):
                                set.setValue(unicode(profileParser.get('preference', set.getName()), 'utf-8', 'replace'))
-               elif set.isMachineSetting():
-                       if profileParser.has_option('machine', set.getName()):
-                               set.setValue(unicode(profileParser.get('machine', set.getName()), 'utf-8', 'replace'))
+
+       n = 0
+       while profileParser.has_section('machine_%d' % (n)):
+               for set in settingsList:
+                       if set.isMachineSetting():
+                               if profileParser.has_option('machine_%d' % (n), set.getName()):
+                                       set.setValue(unicode(profileParser.get('machine_%d' % (n), set.getName()), 'utf-8', 'replace'), n)
+               n += 1
+
+       setActiveMachine(int(getPreference('active_machine')))
 
 def savePreferences(filename):
+       global settingsList
        #Save the current profile to an ini file
        parser = ConfigParser.ConfigParser()
        parser.add_section('preference')
-       parser.add_section('machine')
-       global settingsList
+
        for set in settingsList:
                if set.isPreference():
                        parser.set('preference', set.getName(), set.getValue().encode('utf-8'))
-               elif set.isMachineSetting():
-                       parser.set('machine', set.getName(), set.getValue().encode('utf-8'))
+
+       n = 0
+       while getMachineSetting('machine_name', n) != '':
+               parser.add_section('machine_%d' % (n))
+               for set in settingsList:
+                       if set.isMachineSetting():
+                               parser.set('machine_%d' % (n), set.getName(), set.getValue(n).encode('utf-8'))
+               n += 1
        parser.write(open(filename, 'w'))
 
 def getPreference(name):
@@ -650,12 +697,12 @@ def getMachineSettingFloat(name):
        except:
                return 0.0
 
-def getMachineSetting(name):
+def getMachineSetting(name, index = None):
        if name in tempOverride:
                return tempOverride[name]
        global settingsDictionary
        if name in settingsDictionary and settingsDictionary[name].isMachineSetting():
-               return settingsDictionary[name].getValue()
+               return settingsDictionary[name].getValue(index)
        traceback.print_stack()
        sys.stderr.write('Error: "%s" not found in machine settings\n' % (name))
        return ''
@@ -673,6 +720,34 @@ def isMachineSetting(name):
                return True
        return False
 
+def checkAndUpdateMachineName():
+       global _selectedMachineIndex
+       name = getMachineSetting('machine_name')
+       index = None
+       if name == '':
+               name = getMachineSetting('machine_type')
+       n = 0
+       while getMachineSetting('machine_name', n) != '':
+               if n == _selectedMachineIndex:
+                       continue
+               print name, index, getMachineSetting('machine_name', n)
+               if index is None:
+                       if name == getMachineSetting('machine_name', n):
+                               index = 1
+               else:
+                       if '%s (%d)' % (name, index) == getMachineSetting('machine_name', n):
+                               index += 1
+               n += 1
+       if index is not None:
+               name = '%s (%d)' % (name, index)
+       putMachineSetting('machine_name', name)
+       putPreference('active_machine', _selectedMachineIndex)
+
+def setActiveMachine(index):
+       global _selectedMachineIndex
+       _selectedMachineIndex = index
+       putPreference('active_machine', _selectedMachineIndex)
+
 ## Temp overrides for multi-extruder slicing and the project planner.
 tempOverride = {}
 def setTempOverride(name, value):
index 1b3efc1aa31fdc979e9a530dcd4e7d652bd1dd0e..8944b057af500109d285cbfda646034a0d5982d8 100644 (file)
@@ -243,7 +243,6 @@ class Slicer(object):
                        'insetCount': int(profile.calculateLineCount()),
                        'downSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_bottom') == 'True' else 0,
                        'upSkinCount': int(profile.calculateSolidLayerCount()) if profile.getProfileSetting('solid_top') == 'True' else 0,
-                       'sparseInfillLineDistance': int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density')) if profile.getProfileSettingFloat('fill_density') > 0 else -1,
                        'infillOverlap': int(profile.getProfileSettingFloat('fill_overlap')),
                        'initialSpeedupLayers': int(4),
                        'initialLayerSpeed': int(profile.getProfileSettingFloat('bottom_layer_speed')),
@@ -281,6 +280,16 @@ class Slicer(object):
                        'extruderOffset[3].Y': int(profile.getMachineSettingFloat('extruder_offset_y3') * 1000),
                        'fixHorrible': 0,
                }
+               if profile.getProfileSettingFloat('fill_density') == 0:
+                       settings['sparseInfillLineDistance'] = -1
+               elif profile.getProfileSettingFloat('fill_density') == 100:
+                       settings['sparseInfillLineDistance'] = settings['extrusionWidth']
+                       #Set the up/down skins height to 10000 if we want a 100% filled object.
+                       # This gives better results then normal 100% infill as the sparse and up/down skin have some overlap.
+                       settings['downSkinCount'] = 10000
+                       settings['upSkinCount'] = 10000
+               else:
+                       settings['sparseInfillLineDistance'] = int(100 * profile.calculateEdgeWidth() * 1000 / profile.getProfileSettingFloat('fill_density'))
                if profile.getProfileSetting('platform_adhesion') == 'Brim':
                        settings['skirtDistance'] = 0
                        settings['skirtLineCount'] = int(profile.getProfileSettingFloat('brim_line_count'))